线程的状态
- 新生状态 : 用new关键字创建一个线程,该线程就处于新建状态
- 就绪状态 : 调用start()方法后线程处于就绪状态,具备了运行的条件,但是没有分配到CPU,处于线程的就绪状态
- 运行状态 : 处于就绪状态的线程获得了CPU的执行权,开始执行run方法中的线程执行体,该线程就处于运行状态。
- 阻塞状态
- 1.当线程调用了一个阻塞式的IO方法时,该线程就会进入阻塞状态。
- 2.当线程调用了某个对象的wait()方法时,也会进入阻塞状态,如果想进入就绪状态就会需要调用notify()或者notifyAll()方法唤醒线程
- 3.当线程调用Thread的sleep()方法时,也会进入阻塞状态。
- 4.当一个线程调用了另一个线程的join()方法,也会进入阻塞状态,这种情况下,需要等待新加入的线程运行结束后才会结束阻塞状态,进入就绪状态
- 死亡状态 : 线程的run()方法执行完毕或者抛出一个未捕获的异常、错误,线程就会进入死亡状态。
线程的优先级
- 线程的优先级用1-10之间的整数表示,数字越大优先级越高。
- 调用Thread类中getPriority()查看线程的优先级。线程默认优先级是5
- 调用Thread类中setPriority()方法修改线程的优先级
线程让步
使用yield()方法实现。这个方法和sleep方法类似,都可以让当前的线程暂停。区别在于yield()方法不会阻塞该线程,只是将线程转换为就绪状态。当某个线程调用yield()方法之后,只有与当前线程优先级相同的或者更高的线程才能获得执行的机会。
public class ThreadDemo extends Thread{ public ThreadDemo(String name) { super(name);//调用父类的构造方法 } @Override public void run() { for(int i=0;i<5;i++){ System.out.println(Thread.currentThread().getName()+"---"+i); if(i==3){ System.out.println("线程让步"); Thread.yield(); //线程运行到这里,开始做出让步 } } } } public static void main(String[] args) { ThreadDemo t1=new ThreadDemo("线程一"); ThreadDemo t2=new ThreadDemo("线程二"); t1.start(); t2.start(); }
运行结果:
线程插队
- 调用join()方法实现线程插队功能
调用join()方法后,线程会处于阻塞状态,直到被join方法加入的线程执行完它才会继续执行。
public class ThreadDemo implements Runnable { @Override public void run() { for (int i = 0; i < 6; i++) { System.out.println(Thread.currentThread().getName() + "输入" + i); try { Thread.sleep(500); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } } } } public static void main(String[] args) { ThreadDemo threadDemo = new ThreadDemo(); Thread t1 = new Thread(threadDemo); t1.start(); for (int i = 1; i < 6; i++) { System.out.println(Thread.currentThread().getName() + "输入" + i); if (i == 2) { try { t1.join(); // 调用join方法 Thread.sleep(500); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } } } }
运行结果:
- 从运行结果可以看出,当main线程中的循环变量执行到2时,调用t1线程的join方法,这时t1线程就会插队优先执行,直到t1线程执行完毕,main线程才开始继续执行。
多线程通信问题的解决
假设这样一个场景,一个生产车间,生产一瓶哇哈哈,然后销售一瓶哇哈哈。下面我们来模拟这个过程。
商品类
-
public class Commodity {
private String name; //商品名称
private int num; //商品数量
/**
* 销售
* @return
*/
public synchronized String market(){
System.out.println(“销售第”+num+”瓶”+name);
return name+num;
}
public synchronized void production(String name,int num){
this.name=name;
this.num=num;
System.out.println(“生产第”+num+”瓶——–>”+name);
}
} 工厂类
public class Producer implements Runnable{ Commodity commodity; public Producer(Commodity commodity) { // TODO Auto-generated constructor stub this.commodity=commodity; } @Override public void run() { // TODO Auto-generated method stub int num=1; while(true){ commodity.production("哇哈哈", num++); try { Thread.sleep(500); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } } } }
销售类
public class Market implements Runnable{ Commodity commodity; public Market(Commodity commodity) { this.commodity=commodity; } @Override public void run() { while(true){ commodity.market(); try { Thread.sleep(500); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } } } }
*测试类
public class Test { public static void main(String[] args) { Commodity commodity=new Commodity(); Producer p=new Producer(commodity); Market m=new Market(commodity); Thread t1=new Thread(p,"生产"); Thread t2=new Thread(m,"销售"); t1.start(); t2.start(); } }
- 运行结果:
- 从上面的运行结果可以看出,第5瓶饮料生产完后,第5瓶哇哈哈被销售了两次,显然不符合常理。这时候我们就需要使用Object类中提供的wait()、notify()、notifyAll()方法来解决线程间的通信问题。
首先介绍这几个方法的作用
- void wait() 使当前线程放弃同步锁并进入等待,直到其他线程进入此同步锁,并调用notify()方法或notifyAll()方法唤醒该线程。
- void notify() 唤醒此同步锁上等待的第一个调用wait()方法的线程
- void notifyAll() 唤醒此同步锁上调用wait()方法的所有线程。
接下来我们来完善上面的程序
- 商品类
public class Commodity { private String name; //商品名称 private int num; //商品数量 private boolean flag=false; /** * 销售 * @return */ public synchronized String market(){ if(!flag){ try { wait(); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } } System.out.println("销售第"+num+"瓶"+name); flag=false; notify(); return name+num; } public synchronized void production(String name,int num){ if(flag){ try { wait(); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } } System.out.println("生产第"+num+"瓶-------->"+name); this.name=name; this.num=num; flag=true; notify(); } }
工厂类
public class Producer implements Runnable{ Commodity commodity; public Producer(Commodity commodity) { // TODO Auto-generated constructor stub this.commodity=commodity; } @Override public void run() { // TODO Auto-generated method stub int num=1; while(true){ commodity.production("哇哈哈", num++); try { Thread.sleep(500); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } } } }
销售类
public class Market implements Runnable{ Commodity commodity; public Market(Commodity commodity) { this.commodity=commodity; } @Override public void run() { while(true){ commodity.market(); try { Thread.sleep(500); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } } } }
测试类
public class Test { public static void main(String[] args) { Commodity commodity=new Commodity(); Producer p=new Producer(commodity); Market m=new Market(commodity); Thread t1=new Thread(p,"生产"); Thread t2=new Thread(m,"销售"); t1.start(); t2.start(); } }
- 运行结果:
- 现在的运行结果就合理了,生产一瓶销售一瓶。