线程通信
1、线程通信:不同的线程执行不同的任务,如果这些任务有某种关系,线程之间必须能够通信,协调完成工作,线程通信是相互间状态的切换。
2、线程通信-wait和notify方法介绍:
java.lang.Object类提供类两类用于操作线程通信的方法.
wait():执行该方法的线程对象释放同步锁,JVM把该线程存放到等待池中,等待其他的线程唤醒该线程(失去CPU和锁).
notify:执行该方法的线程随机唤醒在等待池中等待的任意一个线程,把线程转到锁池中等待.
notifyAll():执行该方法的线程唤醒在等待池中等待的所有的线程,把线程转到锁池中等待.
!注意:上述方法只能被同步监听锁对象来调用,否则报错IllegalMonitorStateException...
3、生产者与消费者案例分析:
为什么生产者不直接把数据给消费者,而是先把数据存储到共享资源中,然后,消费者再从共享资源中取出数据,再消费.
在这里体现了面向对象的设计理念:低耦合.
高(紧)耦合: 直接使用生产者把肉包子给消费者,那么生产者中得存在消费者的引用,同理,消费者要消费生产者生产的肉包子,消费者中也得存在生产者对象的引用.
低(松)耦合:使用一个中间对象,屏蔽了生产者和消费者直接的数据交互.
Demo:
public class ThreadDemo1 {
public static void main(String[] args) {
Product pro = new Product();
Producers ps = new Producers(pro);
Salers ss = new Salers(pro);
Thread th1 = new Thread(ps);
Thread th2 = new Thread(ss);
th1.start();
th2.start();
}
}
class Product {
private int id;
private String name;
private boolean flag;
private int i;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public boolean isFlag() {
return flag;
}
public void setFlag(boolean flag) {
this.flag = flag;
}
//produce
synchronized public void produce() {
if (this.isFlag()) {
try {
this.wait();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
this.setName("小火炮");
this.setId(++i);
System.out.println("produce: "+this.getName()+this.getId());
this.setFlag(true);
this.notify();
}
//sale
synchronized public void sale() {
if (!this.isFlag()) {
try {
this.wait();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
System.out.println("sale: "+this.getName()+this.getId());
this.setFlag(false);
this.notify();
}
}
class Producers implements Runnable{
private Product pro;
public Producers(Product pro) {
this.pro = pro;
}
@Override
public void run() {
while(true) {
pro.produce();
}
}
}
class Salers implements Runnable{
private Product pro;
public Salers(Product pro) {
this.pro = pro;
}
@Override
public void run() {
while(true) {
pro.sale();
}
}
}
4、线程通信-使用Lock和Condition接口:
wait和notify方法,只能被同步监听锁对象来调用,否则报错IllegalMonitorStateException.
那么现在问题来了,Lock机制根本就没有同步锁了,也就没有自动获取锁和自动释放锁的概念.
因为没有同步锁,所以Lock机制不能调用wait和notify方法.
解决方案:Java5中提供了Lock机制的同时提供了处理Lock机制的通信控制的Condition接口.
1):使用Lock机制取代synchronized 代码块和synchronized 方法.
2):使用Condition接口对象的await,signal,signalAll方法取代Object类中的wait,notify,notifyAll方法.
Demo:
多个生产者和消费者案例:
//产品: public class Product { private String name; private String country; private boolean isEmpty = true; Lock lock = new ReentrantLock(); Condition cd_p = lock.newCondition(); Condition cd_s = lock.newCondition(); public void pro(String n, String c){ lock.lock(); try { while(!isEmpty){ cd_p.await(); } name = n; Thread.sleep(10); country = c; isEmpty = false; cd_s.signalAll(); } catch (Exception e) { e.printStackTrace(); }finally{ lock.unlock(); } } public void sale(){ lock.lock(); try { while(isEmpty){ cd_s.await(); } Thread.sleep(10); System.out.println(this.name+"---"+this.country); isEmpty = true; cd_p.signalAll(); } catch (Exception e) { e.printStackTrace(); }finally{ lock.unlock(); } } }
//消费者: public class Consumer extends Thread{ Product p = null; public Consumer(Product p) { this.p = p; } public void run() { for (int i = 0; i <25; i++) { p.sale(); } } }
//生产者: public class Producer extends Thread{ Product p = null; public Producer(Product p) { this.p = p; } public void run() { for(int i = 0; i <25; i++){ if(i%2==0){ p.pro("火炮", "中国"); }else{ p.pro("香肠", "四川"); } } } }
//测试类 public class Test { public static void main(String[] args) { Product p = new Product(); new Consumer(p).start(); new Consumer(p).start(); new Producer(p).start(); new Producer(p).start(); } }