线程之间的通讯
1.什么是线程通信
线程之间通信的两个基本问题是互斥和同步。
线程同步是指线程之间所具有的一种制约关系,一个线程的执行依赖另一个线程的消息,当它没有得到另一个线程的消息时应等待,直到消息到达时才被唤醒。
2.syncrhoized加锁的线程的Object类的wait()/notify()/notifyAll()
1)wait()、notify()和notifyAll()方法是本地方法,并且为final方法,无法被重写。
2)调用某个对象的wait()方法能让当前线程阻塞,并且当前线程必须拥有此对象的monitor(即锁)
3)调用某个对象的notify()方法能够唤醒一个正在等待这个对象的monitor的线程,如果有多个线程都在等待这个对象的monitor,则只能唤醒其中一个线程;
4)调用notifyAll()方法能够唤醒所有正在等待这个对象的monitor的线程;
如果调用某个对象的wait()方法,当前线程必须拥有这个对象的monitor(即锁),因此调用wait()方法必须在同步块或者同步方法中进行(synchronized块或者synchronized方法)。如果当前线程没有这个对象的锁就调用wait()方法,则会抛出IllegalMonitorStateException.
调用某个对象的wait()方法,相当于让当前线程交出(释放)此对象的monitor,然后进入等待状态,等待后续再次获得此对象的锁(Thread类中的sleep方法使当前线程暂停执行一段时间,从而让其他线程有机会继续执行,但它并不释放对象锁);
notify()方法能够唤醒一个正在等待该对象的monitor的线程,当有多个线程都在等待该对象的monitor的话,则只能唤醒其中一个线程,具体唤醒哪个线程则不得而知。 同样地,调用某个对象的notify()方法,当前线程也必须拥有这个对象的monitor,因此调用notify()方法必须在同步块或者同步方法中进行(synchronized块或者synchronized方法)。
nofityAll()方法能够唤醒所有正在等待该对象的monitor的线程,这一点与notify()方法是不同的。
3.案例:生产者消费者交替执行
商品:
package threadTest.test2;
public class Goods {
private String name;
private Integer price;
private boolean hav=false;
public synchronized void make(String name,Integer price) {
if(hav) {
try {
wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
this.name=name;
this.price=price;
this.hav=true;
System.out.println("生产者生产:"+this.getName()+"--"+this.price);
notify();
}
public synchronized void xiaofei() {
if(!hav) {
try {
wait();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
System.out.println("消费者消费:"+this.name+"--"+this.price);
this.hav=false;
notify();
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Goods() {
super();
// TODO Auto-generated constructor stub
}
public Integer getPrice() {
return price;
}
public void setPrice(Integer price) {
this.price = price;
}
public boolean isHav() {
return hav;
}
public void setHav(boolean hav) {
this.hav = hav;
}
}
//生产者
package threadTest.test2;
public class ShengChanZhe implements Runnable{
private Goods goods;
public ShengChanZhe(Goods goods) {
this.goods=goods;
}
@Override
public void run() {
// TODO Auto-generated method stub
for(int i=0;i<10;i++) {
if(i%2==0) {
goods.make("手机",1500);
}else {
goods.make("电脑",4560);
}
}
}
}
消费者
package threadTest.test2;
public class XiaoFeiZhe implements Runnable{
private Goods goods;
public XiaoFeiZhe(Goods goods) {
this.goods=goods;
}
@Override
public void run() {
// TODO Auto-generated method stub
for(int i=0;i<10;i++) {
goods.xiaofei();
}
}
}
测试代码:
package threadTest.test2;
public class Test1 {
public static void main(String[] args) {
Goods g=new Goods();
Thread t=new Thread(new ShengChanZhe(g));
t.setName("生产者");
t.start();
Thread t2=new Thread(new XiaoFeiZhe(g));
t2.setName("消费者");
t2.start();
}
}