Java多线程探究-Lock对象锁条件变量
来源:互联网 发布:linux交叉编译环境 编辑:程序博客网 时间:2024/06/05 13:32
Lock锁的条件变量
设想这样的一种情况,现在有一个盘子,一个线程负责往盘子里放一个苹果,一个线程从盘子取一个苹果,如何保证线程A放一个苹果,线程B就把这个苹果取了,不会出现已经放了好几个了,线程B才一个一个的取,现在限定一个条件,盘子里每次只能放一个苹果,由于两个线程随机执行,不能保证线程A刚放了苹果,线程B就刚好取了。如果用通用的思想的话怎么做呢
应该是加条件判断,线程A每次放的时候,判断盘子里是否有苹果,如果有,则不做处理,线程B执行的时候判断是否有一个苹果,有的话,把这个苹果取了。苹果可以用数字表示,0表示盘子没有苹果,1表示有一个苹果,那么线程A做的事情就是加1,线程B做的就是减1,由于是对同一数据同时操作,必须要用锁保证数据安全
下面是基本的实现
public class ThreadDemo4 { public static void main(String[] args) { int[] apple = new int[]{0}; Object obj = new Object(); new Thread(new Runnable() { @Override public void run() { while(true){ synchronized (obj){ if(apple[0] == 0) { apple[0]++; System.out.println("线程 "+Thread.currentThread().getId()+ " 放了一个苹果 "+apple[0]); }else{ System.out.println("线程 "+Thread.currentThread().getId()+ " 放苹果,已经有苹果"); } try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } } } } }).start(); new Thread(new Runnable() { @Override public void run() { while(true){ synchronized (obj){ if(apple[0] == 1) { apple[0]--; System.out.println("线程 "+Thread.currentThread().getId()+ " 取了一个苹果 "+apple[0]); }else{ System.out.println("线程 "+Thread.currentThread().getId()+ " 取苹果,没有苹果..."); } try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } } } } }).start(); }}
打印结果
从打印结果来看,虽然线程12可以取到苹果,但是并不是都是在线程11刚放入就能取到,从第三行开始,线程12取了好几次都没有取到,这是因为CPU时间片此时被线程12占有,线程11没有执行的时间片,也就不能放苹果了,但是这样的话,会导致资源的消耗,明知没有苹果,那么线程12应该不用再取了,而是等待线程11放了一个苹果后再取,如果线程12发现没苹果了,就不再继续取了,而是等待线程11放苹果,放完之后,你给我发个通知,我再取,由于两个线程都是随机执行的,没法保证按顺序一放一取。怎么才能做到呢?这就是著名的多线程生产者和消费者问题
Java的Object提供了几个方法,用来做线程件的通信
public final native void notify(); 唤醒一个正在等待的线程,如果有多个等待的线程,那么会随机唤醒了一个,这些线程唤醒之后继续尝试获得锁的占有权,进入同步块
public final native void notifyAll(); 唤醒所有等待的线程
public final void wait() throws InterruptedException 释放锁,进入线程等待池,等待被别的线程notify
JDK1.5提供了一个对象锁的条件变量,类似Object的wait,nofity,notifyAll
类Condition的方法
下面是一个常见的面试题
如何用两个线程依次打印出100以内的奇数和偶数,一个线程打印奇数,另一个打印偶数,前面说了如果不用wait和notify的话,没法控制线程的顺序执行和条件执行,很可能一个线程打印了几次,另外一个才打印一次
现在使用Condition条件变量来实现
class Obj { public int state = 1;}class ThreadA implements Runnable { private int numA = 0; private Obj obj; private Lock lock; private Condition condition; public ThreadA(Obj obj, Lock lock, Condition condition) { this.obj = obj; this.lock = lock; this.condition = condition; } @Override public void run() { while (numA < 100) { lock.lock(); try { if (obj.state != 1) { condition.await(); } else { System.out.println(Thread.currentThread().getName() + " >>> " + numA); Thread.sleep(100); numA += 2; obj.state = 2; condition.signal(); } } catch (InterruptedException e) { e.printStackTrace(); } finally { lock.unlock(); } } }}class ThreadB implements Runnable { private int numB = 1; private Obj obj; private Lock lock; private Condition condition; public ThreadB(Obj obj, Lock lock, Condition condition) { this.obj = obj; this.lock = lock; this.condition = condition; } @Override public void run() { while (numB < 100) { lock.lock(); try { if (obj.state != 2) { condition.await(); } else { System.out.println(Thread.currentThread().getName() + " >>> " + numB); Thread.sleep(100); numB += 2; obj.state = 1; condition.signal(); } } catch (InterruptedException e) { e.printStackTrace(); } finally { lock.unlock(); } } }}public class ThreadDemo2 { public static void main(String[] args) { Obj obj = new Obj(); Lock lock = new ReentrantLock(); Condition d1 = lock.newCondition(); Runnable a = new ThreadA(obj, lock, d1); Runnable b = new ThreadB(obj, lock, d1); Thread t1 = new Thread(a, "Thread-A"); Thread t2 = new Thread(b, "Thread-B"); t1.start(); t2.start(); }}
输出结果
这样就实现了顺序打印
总结:如果需要让多个线程按条件顺序执行,就需要使用锁对象的wait
,notify
方法
关于生成者消费者模型,看我的另外一篇博客
- Java多线程探究-Lock对象锁条件变量
- Java多线程探究-Lock锁对象
- Java多线程----java 对象锁(synchronized/lock)
- java 多线程------条件变量
- Java多线程 -- 条件变量
- Java多线程Lock对象之读写锁
- JAVA--多线程同步,锁对象,条件对象
- Java多线程 同步 锁 条件对象
- Java多线程探究-线程局部变量ThreadLocal
- Java多线程开发六——锁、条件变量、信号量
- Java多线程Lock对象之ReentrantLock(1)
- Java多线程Lock对象之ReentrantLock(2)
- Java多线程Lock对象常用方法(1)
- Java多线程Lock对象常用方法(2)
- Java多线程Lock对象常用方法(3)
- Java多线程Lock对象常用方法(4)
- 《深入浅出 Java Concurrency》—锁机制(四) 锁释放与条件变量 (Lock.unlock And Condition)
- 《深入浅出 Java Concurrency》—锁机制(四) 锁释放与条件变量 (Lock.unlock And Condition)
- VBA代码实例---根据分数判断等级
- React Native网络请求(Frisbee网络框架)
- echarts异步数据加载和更新
- gpio模拟SPI
- 打不同包名的包
- Java多线程探究-Lock对象锁条件变量
- JS的内建函数reduce
- ThinkPHP5 common.php写公共函数遇到的坑
- C#和C++结构体Socket通信
- Android 格式化分区命令
- 11 And 11!(0259)
- C语言实现顺序表--静态
- JAVA——从小白开始
- 长URL转短连接的简单设计与实现