线程入门
1.创建线程的三种方式
1.1 继承Thread类,重写run()
public class ExtendThread extends Thread { //继承Thread类@Overridepublic void run() { //重写run()方法, run()方法中包含线程的执行体for (int i = 0; i < 1000; i++) {System.out.println("画圆");}}public static void main(String[] args) {//创建实例,start()使线程进入就绪状态ExtendThread extendThread = new ExtendThread();extendThread.start();//main线程,用于与创建的线程对比for (int i = 0; i < 1000; i++) {System.out.println("画方");}}}
1.2 实现Runnable接口,重写run()
public class ImplementsRunnable implements Runnable {//重写run(), run()方法中包含线程的执行体@Overridepublic void run() {//Thread.sleep()使线程休眠,模拟延时try {Thread.sleep(500);} catch (InterruptedException e) {e.printStackTrace();}for (int i = 0; i < 20; i++) {System.out.println("画圆");}}public static void main(String[] args) {//创建实现接口的实例ImplementsRunnable implementsRunnable = new ImplementsRunnable();//创建线程的语法//Thread thread = new Thread(runnable);//start()使线程进入就绪状态//thread.start();//简化为下new Thread((implementsRunnable)).start();//main线程,用于与创建的线程对比for (int i = 0; i < 20; i++) {System.out.println("画方块");}}}
应用: 龟兔赛跑
//龟兔赛跑public class Race implements Runnable {static String Winner = null;@Overridepublic void run() {for (int i = 0; i <= 100; i++) {System.out.println(Thread.currentThread().getName() + " 跑了 " + i + " 步");//跑到终点,产生胜者,结束循环if (gameOver(i)) {Winner = Thread.currentThread().getName();System.out.println(Winner+" 赢了");break;}//已存在胜者,结束循环if (Winner != null) {break;}}}private boolean gameOver(int step) {if (step >= 100) {return true;} else {return false;}}public static void main(String[] args) {Race race = new Race();new Thread(race,"兔子").start();new Thread(race,"乌龟").start();}}
1.3 实现Callable接口,重写call()
public class ImplementsCallable implements Callable<Integer> { //Callable后加上泛型//该 call() 方法将作为线程执行体,并且有返回值。@Overridepublic Integer call() throws Exception {int i;for (i = 0; i < 10; i++) {System.out.println(Thread.currentThread().getName()+" "+i);}return i;}public static void main(String[] args) {//创建 Callable接口实现类的实例ImplementsCallable ctt = new ImplementsCallable();//使用 FutureTask 类来包装 Callable 对象,该 FutureTask 对象封装了该 Callable 对象的 call() 方法的返回值//类似C++中容器FutureTask<Integer> ft = new FutureTask<>(ctt);for (int i = 0; i < 100; i++) {System.out.println(Thread.currentThread().getName() + " 的循环变量i的值" + i);if (i == 20) {//使用 FutureTask类的对象作为 Thread 对象的 target 创建并启动新线程new Thread(ft, "有返回值的线程").start();}}//调用 FutureTask 对象的 get() 方法来获得子线程执行结束后的返回值try {System.out.println("子线程的返回值:" + ft.get());} catch (Exception e) {e.printStackTrace();}}}
2.操作线程
sleep()
Thread.sleep(millis);
用sleep()模拟网络延时,放大问题的发生可能性
每个对象都有一把锁,sleep()不会释放锁,类似于抱着锁睡觉
//应用: 模拟倒计时public class CountDown {public static void main(String[] args) {count(10);}static void count(int time) {for (; time >= 0; time--) {try {Thread.sleep(1000); // 模拟延时, 1000ms} catch (InterruptedException e) {e.printStackTrace();}System.out.println(time + " second left...");}}}
stop()
在Runnable的实现类中定义标志位, 并定义一个用于转换标志位停止线程的stop()方法, 在线程体run()中通过判断标志位状态来控制线程
public class ThreadStop implements Runnable {//定义标志位boolean flag = true;//线程体@Overridepublic void run() {//线程体使用标志位控制while (flag) {//循环输出,直至主线程中for循环到第80次System.out.println("Thread is running...");}}//定义一个公开的stop()方法,用于转换标志位,停止线程public void stop() {this.flag = false;System.out.println("分线程停止了");}public static void main(String[] args) {ThreadStop runnable = new ThreadStop();Thread thread = new Thread(runnable);thread.start();//主线程for (int i = 0; i < 100; i++) {System.out.println("main is running..." +i);if (i == 80) {//stop方法,转换标志位runnable.stop();}}}}
getState()
线程的六种基本状态:
新建状态(New) 即用new关键字新建一个线程,这个线程就处于新建状态。
就绪状态(Runnable) 操作系统中的就绪和运行两种状态,在Java中统称为RUNNABLE。
等待状态(WAITING) 进入该状态表示当前线程需要等待其他线程做出一些的特定的动作(通知或中断)。
超时等待状态(TIMED_WAITING) 区别于WAITING,它可以在指定的时间自行返回。
阻塞状态(Blocked) 阻塞状态表示线程正等待监视器锁,而陷入的状态。
消亡状态(Dead) 即线程的终止,表示线程已经执行完毕。
使用getState()方法能够获得线程当前所处的状态
public class ThreadState {public static void main(String[] args) throws InterruptedException {//使用lambda表达式,创建Thread实例,重写run()方法Thread thread = new Thread(() -> {for (int i = 0; i < 50; i++) {if (i % 5 == 0) {try {Thread.sleep(100); //3.TIMED_WAITING} catch (InterruptedException e) {e.printStackTrace();}}}System.out.println("---------------------");//4.TERMINATED});System.out.println("thread.getState() = " + thread.getState()); //1.NEWthread.start(); //2.RUNNABLEwhile (thread.getState() != Thread.State.TERMINATED) {System.out.println("thread.getState() = " + thread.getState());Thread.sleep(100);}}}
setPriority()
使用setPriority()方法来设置线程的优先级
setPriority()方法的参数为可以为Thread的枚举类型属性, 或是1~10的整数, 数字越大优先级越高
public class ThreadPriority {public static void main(String[] args) {//主线程默认优先级System.out.println(Thread.currentThread().getName()+" --> "+ Thread.currentThread().getPriority());MyPriority myPriority = new MyPriority();Thread t1 = new Thread(myPriority, "t1");Thread t2 = new Thread(myPriority, "t2");Thread t3 = new Thread(myPriority, "t3");Thread t4 = new Thread(myPriority, "t4");//先设置优先级再启动t1.start();t2.setPriority(1);t2.start();t3.setPriority(4);t3.start();t4.setPriority(Thread.MAX_PRIORITY);t4.start();}}class MyPriority implements Runnable {@Overridepublic void run() {//执行体打印当前线程名和优先级System.out.println(Thread.currentThread().getName()+" --> "+ Thread.currentThread().getPriority());}}
join()
join()调用合并线程,其他线程阻塞, 待调用join的线程执行完毕后,再执行其他线程,类似插队
public class ThreadJoin implements Runnable {public static void main(String[] args) throws InterruptedException {ThreadJoin threadJoin = new ThreadJoin();Thread thread = new Thread(threadJoin, "分线程");thread.start();for (int i = 0; i < 200; i++) {//main线程的i=100时,分线程插入,main线程阻塞if (i == 100) thread.join();//分线程完全结束后,main线程继续执行System.out.println("main is running..." + i);}}@Overridepublic void run() {for (int i = 0; i < 50; i++) {System.out.println(Thread.currentThread().getName() + " is running..." + i);}}}
yield()
yield()使得线程礼让,让运行状态的线程重新进入就绪状态, 等待CPU的调度
public class ThreadYield {public static void main(String[] args) {MyYield myYield = new MyYield();new Thread(myYield,"Apple").start();new Thread(myYield,"Google").start();}}class MyYield implements Runnable {@Override//首次运行时从头开始执行run()public void run() {System.out.println(Thread.currentThread().getName()+"线程开始执行。。。");//线程礼让, 暂停线程, 重新进入就绪状态等待调度Thread.yield();//礼让后继续执行yield()语句后的代码System.out.println(Thread.currentThread().getName()+"线程停止执行。。。");}}
setDaemon()
线程分为用户线程(如main…)和守护线程(如垃圾回收机制gc…)
虚拟机不必等待守护线程结束才结束进程
public class ThreadDaemon {public static void main(String[] args) {God god = new God();People people = new People();Thread thread_god = new Thread(god);thread_god.setDaemon(true);//通过setDaemon()方法将thread_god线程设为守护线程Thread thread_people = new Thread(people);thread_god.start();thread_people.start();}}class God implements Runnable {@Overridepublic void run() {//发现死循环并不会一直执行,到用户线程结束即结束while (true) {try {Thread.sleep(100);} catch (InterruptedException e) {e.printStackTrace();}System.out.println("god bless you!");}}}class People implements Runnable {@Overridepublic void run() {for (int i = 0; i < 100; i++) {try {Thread.sleep(100);} catch (InterruptedException e) {e.printStackTrace();}System.out.println("I am happy!");}System.out.println("Goodbye World!");}}
3.线程池
创建线程池使用Executors.newFixedThreadPool(nThread) 静态工厂方法,参数为池子大小
public class ThreadPool {public static void main(String[] args) {//1.创建服务,创建线程池// Executors.newFixedThreadPool() 静态工厂方法,参数为池子大小ExecutorService service = Executors.newFixedThreadPool(10);//2.将线程放入线程池service.execute(new MyRunnable());service.execute(new MyRunnable());service.execute(new MyRunnable());service.execute(new MyRunnable());//3.关闭线程池service.shutdown();}}class MyRunnable implements Runnable {@Overridepublic void run() {System.out.println(Thread.currentThread().getName() + " is running...");}}
4.锁
在并发编程中存在线程安全问题,主要原因有:1.存在共享数据 2.多线程共同操作共享数据。
当多线程同时操作同一个对象, 会导致数据紊乱, 线程不安全, 故引入锁
为了解决这些问题, 引入了Synchronized和ReentrantLock两种方式
Synchronized
语法为: synchronized (需要上锁的对象) { 代码块 }
public class BuyTicket implements Runnable {//票数private Integer ticketNum = 20;@Overridepublic void run() {//循环抢票while (true) {//引入锁//使用synchronized锁上ticketNum,使得多个线程不能同时对ticketNum进行操作//执行完一次代码块中的内容就释放锁synchronized (ticketNum) {if (ticketNum <= 0) {break;}System.out.println(Thread.currentThread().getName() + "拿到了第" + (ticketNum--) + "张票");}}}public static void main(String[] args) {//创建Runnable对象BuyTicket buyTicket = new BuyTicket();//三个线程操作一个Runnable对象new Thread(buyTicket, "小红").start();new Thread(buyTicket, "小黄").start();new Thread(buyTicket, "小蓝").start();}}
ReentrantLock
public class LockDemo {public static void main(String[] args) {//创建Runnable对象Ticket ticket = new Ticket();//三个线程操作一个Runnable对象new Thread(ticket, "小红").start();new Thread(ticket, "小黄").start();new Thread(ticket, "小蓝").start();}}class Ticket implements Runnable {private int number = 1000;//定义ReentrantLock类的Lock锁private ReentrantLock lock = new ReentrantLock();@Overridepublic void run() {while (true) {try {//lock()加锁lock.lock();//加锁后判断,不能让多个线程同时判断if (number <= 0) {System.out.println(Thread.currentThread().getName() + "--> 没票了");break;}System.out.println(Thread.currentThread().getName() + " 拿到了 " + (number--) + " 号票");//unlock()解锁lock.unlock();} catch (Exception e) {e.printStackTrace();}}}}
5.死锁
多个线程互相持有对方所需要的资源,相互等待,形成僵持
public class DeadLock {public static void main(String[] args) {Thread lea = new Thread(new Girl("Lea", 1));Thread anna = new Thread(new Girl("Anna", 0));lea.start();anna.start();}}//镜子类class Mirror {}//口红类class LipStick {}class Girl implements Runnable {private String name;private int choice;//mirror,lipStick设为static,表示只有一个镜子和口红static Mirror mirror = new Mirror();static LipStick lipStick = new LipStick();//构造器 choice=0或1public Girl(String name, int choice) {this.name = name;this.choice = choice;}@Overridepublic void run() {makeup();}void makeup() {//choice为0,先获得镜子的锁,再等待拿口红的锁if (choice == 0) {synchronized (mirror) {//获得镜子锁System.out.println(this.name + " 获得了镜子的锁");try {Thread.sleep(100);//模拟延时,保证另一个人拿到了另一件物品的锁} catch (InterruptedException e) {e.printStackTrace();}//锁中拿锁,造成死锁synchronized (lipStick) {//获得口红锁System.out.println(this.name + " 获得了口红的锁");}}} else {synchronized (lipStick) {//获得口红锁System.out.println(this.name + " 获得了口红的锁");try {Thread.sleep(200);//模拟延时,保证另一个人拿到了另一件物品的锁} catch (InterruptedException e) {e.printStackTrace();}//锁中拿锁,造成死锁synchronized (mirror) {//获得镜子锁System.out.println(this.name + " 获得了镜子的锁");}}}}}
