线程的同步与协作,这个概念很普通就是说,一个线程需要等另一个线程完成或者完成某部分时才能继续工作。
线程之间的同步与协作,有一个经典的场景:生产者与消费者。如库存不足,那么消费者线程需要等待,生产者生产出足够的物品。生产者和消费者都需要访问物品库,同一时刻(在某个操作下)只能有一个线程占用。 既然是线程,那么线程运行CPU时间片不怎么好控制,涉及到数据安全还需要涉及到锁。临界资源只能有一个线程占用,那么等待的线程需要释放锁,但又要保留线程当前的运算结果中间值。使用wait方法,释放线程占用的资源,进入阻塞状态,等待生产者线程唤醒,然后重新去抢占锁等其他资源就使用条件(Condition)便于线程间通信,来实现
因为缺钱,就拿取钱作为例子。
这是账户代码,取钱和存钱
package com.Thread.sync; import java.util.concurrent.locks.Condition; import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReentrantLock; public class Accout { private Lock lock = new ReentrantLock(true); private Condition newDeposit = lock.newCondition(); // 创建一个条件 private int money=100; public void addMoney(int aum){ lock.lock(); try { Thread.sleep(1000); money=money+aum; newDeposit.signalAll(); System.out.println(" 存 "+aum+" 元 现在余额共:"+money); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); }finally{ lock.unlock(); } } /** *取款是一定要成功的,不成功便等待 * @param put */ public void putMoney(int put){ lock.lock(); try { Thread.sleep(1000); //代表历史处理过的逻辑, System.out.println("取钱之前的准备工作。。。。"); while(money<put){ System.out.println("取出 "+put+" 元" +" 余额不足无法取出 当前余额:"+money); newDeposit.await(); } Thread.sleep(1000); money=money-put; System.out.println("成功取出"+put+" 元 ,余额:"+money+" 元-------------"); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); }finally{ lock.unlock(); } } }
取钱线程
package com.Thread; import java.util.Random; import com.Thread.sync.Accout; public class GetMoney implements Runnable{ private Accout accout; public GetMoney(Accout accout){ this.accout=accout; } @Override public void run() { // TODO Auto-generated method stub int n=10; accout.putMoney(new Random().nextInt(8000)+2000); } }
存钱线程
package com.Thread.sync; import java.util.Random; public class AddMoney implements Runnable{ private Accout accout; public AddMoney(Accout accout) { // TODO Auto-generated constructor stub this.accout=accout; } @Override public void run() { int n=20; while(n>1){ accout.addMoney(new Random().nextInt(2000)); n--; } } }
测试类
package com.Thread.sync; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import com.Thread.GetMoney; public class Sync { public static void main(String[] args) { // TODO Auto-generated method stub Accout accout=new Accout(); ExecutorService executor = Executors.newCachedThreadPool(); executor.execute(new AddMoney(accout)); executor.execute(new GetMoney(accout)); } }
运行结果:
存 587 元 现在余额共:687 取钱之前的准备工作。。。。//证明线程之前的运算被保存,并没有重复运行 取出 2386 元 余额不足无法取出 当前余额:687 存 221 元 现在余额共:908 取出 2386 元 余额不足无法取出 当前余额:908 存 5 元 现在余额共:913 取出 2386 元 余额不足无法取出 当前余额:913 存 1079 元 现在余额共:1992 取出 2386 元 余额不足无法取出 当前余额:1992 存 1145 元 现在余额共:3137 成功取出2386 元 ,余额:751 元------------- 存 197 元 现在余额共:948 存 1029 元 现在余额共:1977 存 1104 元 现在余额共:3081 存 1542 元 现在余额共:4623 存 650 元 现在余额共:5273 存 585 元 现在余额共:5858 存 1096 元 现在余额共:6954 存 1258 元 现在余额共:8212 存 1617 元 现在余额共:9829 存 763 元 现在余额共:10592 存 954 元 现在余额共:11546 存 183 元 现在余额共:11729 存 1815 元 现在余额共:13544 存 1647 元 现在余额共:15191