/** * 线程间通信 * 其实就是多线程在操作同一个资源 * 但是操作的动作不同 * */ class Res { String name; String sex; } class Input implements Runnable { private Res res; Input(Res res) { this.res =res; } @Override public void run() { int x=0; while (true) { if(x==0) { res.name = "mike"; res.sex = "man"; } else { res.name = "丽丽"; res.sex = "女女女女女"; } x = (x+1)%2; } } } class Output implements Runnable { private Res res; Output(Res res) { this.res =res; } @Override public void run() { while (true) { System.out.println(res.name+"......"+res.sex); } } } class Test { public static void main(String[] args) { Res res = new Res(); Input i = new Input(res); Output o = new Output(res); Thread t1 = new Thread(i); Thread t2 = new Thread(o); t1.start(); t2.start(); } }
运行结果:
线程不安全
代码2线程安全:
class Res { String name; String sex; } class Input implements Runnable { private Res res; Input(Res res) { this.res =res; } @Override public void run() { int x=0; while (true) { synchronized (res) { if(x==0) { res.name = "mike"; res.sex = "man"; } else { res.name = "丽丽"; res.sex = "女女女女女"; } x = (x+1)%2; } } } } class Output implements Runnable { private Res res; Output(Res res) { this.res =res; } @Override public void run() { while (true) { synchronized (res) { System.out.println(res.name+"......"+res.sex); } } } } class Test { public static void main(String[] args) { Res res = new Res(); Input i = new Input(res); Output o = new Output(res); Thread t1 = new Thread(i); Thread t2 = new Thread(o); t1.start(); t2.start(); } }
运行结果:
多线程安全;
需求:放入一个值输出一个值;(多线程通讯:等待唤醒机制)
代码3:
/** * 线程间通信 * 其实就是多线程在操作同一个资源 * 但是操作的动作不同 * * wait(); * notify(); * notifyAll(); * * 都使用在同步中,因为要对持有监视器(锁)的线程操作。 * 所以要使用在同步中,应为只有同步才具有锁。 * * 为什么这些操作线程的方法要定义Object类中呢? * 因为这些方法在操作同步中线程时,都必须要标识他们做操作线程只有的锁。 * 只有同一个锁上的被等待线程,可以被同一个锁上的notify唤醒。 * 不可以对不同锁中的线程进行唤醒。 * * 也就是说,等待和唤醒必须是同一个锁。 * *而锁可以是任意对象,所以可以任意对象调用的方法定义在Object类中。 * */ class Res { String name; String sex; boolean flag=false; } class Input implements Runnable { private Res res; Input(Res res) { this.res =res; } @Override public void run() { int x=0; while (true) { synchronized (res) { if(res.flag) { try { res.wait(); } catch (InterruptedException e) { e.printStackTrace(); } } if(x==0) { res.name = "mike"; res.sex = "man"; } else { res.name = "丽丽"; res.sex = "女女女女女"; } x = (x+1)%2; res.flag=true; res.notify(); } } } } class Output implements Runnable { private Res res; Output(Res res) { this.res =res; } @Override public void run() { while (true) { synchronized (res) { if(!res.flag){ try { res.wait(); } catch (InterruptedException e) { e.printStackTrace(); } } System.out.println(res.name+"......"+res.sex); res.flag = false; res.notify(); } } } } class Test { public static void main(String[] args) { Res res = new Res(); Input i = new Input(res); Output o = new Output(res); Thread t1 = new Thread(i); Thread t2 = new Thread(o); t1.start(); t2.start(); } }
运行结果:
符合需求;
以上代码优化:
代码4:
class Res { private String name; private String sex; private boolean flag=false; public synchronized void set(String name,String sex) { if(flag) { try { this.wait(); } catch (InterruptedException e) { e.printStackTrace();} } this.name = name; this.sex = sex; flag = true; this.notify(); } public synchronized void out() { if(!flag) { try { this.wait(); } catch (InterruptedException e) { e.printStackTrace();} } System.out.println(this.name+"......"+this.sex); flag = false; this.notify(); } } class Input implements Runnable { private Res res; Input(Res res) { this.res =res; } @Override public void run() { int x=0; while (true) { if(x==0) res.set("mike", "man"); else res.set("丽丽", "女女女女女"); x = (x+1)%2; } } } class Output implements Runnable { private Res res; Output(Res res) { this.res =res; } public void run() { while (true) { res.out(); } } } class Test { public static void main(String[] args) { Res res = new Res(); new Thread(new Input(res)).start(); new Thread(new Output(res)).start(); } }
生产消费模式:
多个生产者,多个消费者:
代码5:
/** * 资源 * */ class Resource { private String name; private int count=1; private boolean flag = false; public synchronized void set(String name) { while(flag) { try {wait();//放弃执行权 注意:当被唤醒后,获得执行权接着往下执行,并持有共同锁 } catch (InterruptedException e) { e.printStackTrace(); } } this.name = name+"--"+count++; System.out.println(Thread.currentThread().getName()+"...生产者.."+this.name); flag = true; notify(); } public synchronized void out() { while(!flag) { try {wait(); } catch (InterruptedException e) { e.printStackTrace(); } } System.out.println(Thread.currentThread().getName()+"...消费者......"+this.name); flag = false; notify(); } } /** * 生产者 * */ class Producer implements Runnable { private Resource res; Producer(Resource res) { this.res = res; } public void run() { while (true) { res.set("+商品+"); } } } /** * 消费者 * */ class Consumer implements Runnable { private Resource res; Consumer(Resource res) { this.res = res; } public void run() { while (true) { res.out(); } } } /** * 测试 * */ class Test { public static void main(String[] args) { Resource r = new Resource(); Producer pro = new Producer(r); Consumer con = new Consumer(r); Thread t1 = new Thread(pro); Thread t2 = new Thread(pro); Thread t3 = new Thread(con); Thread t4 = new Thread(con); t1.start(); t2.start(); t3.start(); t4.start(); } }
运行结果:
没有反应了,原因是 这几个线程都放弃执行权了;
解决以上问题:
将notify()方法,修改为notifyAll()(比较通用的方式);
运行结果图:
运行结果OK了;
问题1:但是 notifyAll唤醒了所有线程包括本方的线程,要怎样使生产者线程运行完唤醒消费者线程而不是全都唤醒?
用Lock来替代sysynchronized :
代码4使用lock实现方式:
代码6使用lock实现多线程 生产消费模式 一对一:
import java.util.concurrent.locks.Condition; import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReentrantLock; /** * 资源 * */ class Resource { private String name; private int count=1; private boolean flag = false; private Lock lock = new ReentrantLock(); private Condition condition = lock.newCondition(); public void set(String name) throws InterruptedException { lock.lock(); try { while(flag) { condition.await(); } this.name = name+"--"+count++; System.out.println(Thread.currentThread().getName()+"...生产者.."+this.name); flag = true; condition.signal();//唤醒 下一个线程 } finally { lock.unlock();//释放资源 } } public void out() throws InterruptedException { lock.lock(); try { while(!flag) condition.await(); System.out.println(Thread.currentThread().getName()+"...消费者......"+this.name); flag = false; condition.signal();//唤醒 下一个线程 } finally { lock.unlock();//释放资源 } } } /** * 生产者 * */ class Producer implements Runnable { private Resource res; Producer(Resource res) { this.res = res; } public void run() { while (true) { try { res.set("+商品+"); } catch (InterruptedException e) { e.printStackTrace(); } } } } /** * 消费者 * */ class Consumer implements Runnable { private Resource res; Consumer(Resource res) { this.res = res; } public void run() { while (true) { try { res.out(); } catch (InterruptedException e) { e.printStackTrace(); } } } } /** * 测试 * */ class Test { public static void main(String[] args) { Resource r = new Resource(); Producer pro = new Producer(r); Consumer con = new Consumer(r); Thread t1 = new Thread(pro); Thread t4 = new Thread(con); t1.start(); t4.start(); } }
代码5的修改版使用lock实现方式:
代码7使用lock实现多线程生产消费模式 多对多:
代码7:
/** * 资源 * */ class Resource { private String name; private int count=1; private boolean flag = false; private Lock lock = new ReentrantLock(); private Condition condition = lock.newCondition(); public void set(String name) throws InterruptedException { lock.lock(); try { while(flag) condition.await(); this.name = name+"--"+count++; System.out.println(Thread.currentThread().getName()+"...生产者.."+this.name); flag = true; condition.signalAll();//唤醒所有使用共享对象的线程 } finally { lock.unlock();//释放资源 } } public void out() throws InterruptedException { lock.lock(); try { while(!flag) condition.await(); System.out.println(Thread.currentThread().getName()+"...消费者......"+this.name); flag = false; condition.signalAll(); } finally { lock.unlock();//释放资源 } } } /** * 生产者 * */ class Producer implements Runnable { private Resource res; Producer(Resource res) { this.res = res; } public void run() { while (true) { try { res.set("+商品+"); } catch (InterruptedException e) { e.printStackTrace(); } } } } /** * 消费者 * */ class Consumer implements Runnable { private Resource res; Consumer(Resource res) { this.res = res; } public void run() { while (true) { try { res.out(); } catch (InterruptedException e) { e.printStackTrace(); } } } } /** * 测试 * */ class Test { public static void main(String[] args) { Resource r = new Resource(); Producer pro = new Producer(r); Consumer con = new Consumer(r); Thread t1 = new Thread(pro);t1.start(); Thread t3 = new Thread(con);t3.start(); Thread t2 = new Thread(pro);t2.start(); Thread t4 = new Thread(con);t4.start(); } }
现在使用lock 的新特性解决代码5中的问题1;
一个lock上可以有多个condition :
代码8:
import java.util.concurrent.locks.Condition; import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReentrantLock; /** * 资源 * JDK1.5 中提供了多线程升级解决方案 * 将synchronized替换成Condition对象。 * 将Object中的wait,notify,nottfyAll,替换了Condition对象。 * 该对象可以使用Lock锁进行获取。 * 该示例中,实现了本方只唤醒对方的操作。 * */ class Resource { private String name; private int count=1; private boolean flag = false; private Lock lock = new ReentrantLock(); private Condition condition_pro = lock.newCondition();//锁条件 private Condition condition_con = lock.newCondition();// public void set(String name) throws InterruptedException { lock.lock(); try { while(flag) condition_pro.await(); this.name = name+"--"+count++; System.out.println(Thread.currentThread().getName()+"...生产者.."+this.name); flag = true; condition_con.signal();//唤醒某个线程 } Finally { lock.unlock();//释放资源 一定要执行 } } public void out() throws InterruptedException { lock.lock(); try { while(!flag) condition_con.await(); System.out.println(Thread.currentThread().getName()+"...消费者......"+this.name); flag = false; condition_pro.signal(); } finally { lock.unlock();//释放资源 } } } /** * 生产者 * */ class Producer implements Runnable { private Resource res; Producer(Resource res) { this.res = res; } public void run() { while (true) { try { res.set("+商品+"); } catch (InterruptedException e) { e.printStackTrace(); } } } } /** * 消费者 * */ class Consumer implements Runnable { private Resource res; Consumer(Resource res) { this.res = res; } public void run() { while (true) { try { res.out(); } catch (InterruptedException e) { e.printStackTrace(); } } } } /** * 测试 * */ class Test { public static void main(String[] args) { Resource r = new Resource(); Producer pro = new Producer(r); Consumer con = new Consumer(r); Thread t1 = new Thread(pro);t1.start(); Thread t3 = new Thread(con);t3.start(); Thread t2 = new Thread(pro);t2.start(); Thread t4 = new Thread(con);t4.start(); } }
Condition 将 Object 监视器方法(wait、notify 和 notifyAll)分解成截然不同的对象,以便通过将这些对象与任意 Lock 实现组合使用,为每个对象提供多个等待 set(wait-set)。其中,Lock 替代了 synchronized 方法和语句的使用,Condition 替代了 Object 监视器方法的使用。
条件(也称为条件队列 或条件变量)为线程提供了一个含义,以便在某个状态条件现在可能为 true 的另一个线程通知它之前,一直挂起该线程(即让其“等待”)。因为访问此共享状态信息发生在不同的线程中,所以它必须受保护,因此要将某种形式的锁与该条件相关联。等待提供一个条件的主要属性是:以原子方式 释放相关的锁,并挂起当前线程,就像 Object.wait 做的那样。
Condition 实例实质上被绑定到一个锁上。要为特定 Lock 实例获得 Condition 实例,请使用其 newCondition() 方法。