java lockobject_多线程通信的两种方式? (可重入锁ReentrantLock和Object)

(一)Java中线程协作的最常见的两种方式:

(1)利用Object的wait()、notify()和notifyAll()方法及synchronized

(2)使用Condition、ReentrantLock

(二)Object类的wait()、notify()和notifyAll()方法

1 /**

2 * Wakes up a single thread that is waiting on this object's3 * monitor. If any threads are waiting on this object, one of them4 * is chosen to be awakened. The choice is arbitrary and occurs at5 * the discretion of the implementation. A thread waits on an object's6 * monitor by calling one of the wait methods7 */

8 public final native voidnotify();9

10 /**

11 * Wakes up all threads that are waiting on this object's monitor. A12 * thread waits on an object's monitor by calling one of the13 * wait methods.14 */

15 public final native voidnotifyAll();16

17 /**

18 * Causes the current thread to wait until either another thread invokes the19 * {@linkjava.lang.Object#notify()} method or the20 * {@linkjava.lang.Object#notifyAll()} method for this object, or a21 * specified amount of time has elapsed.22 *

23 * The current thread must own this object's monitor.24 */

25 public final native void wait(long timeout) throws InterruptedException;

从这三个方法的文字描述可以知道以下几点信息:

1)wait()、notify()和notifyAll()方法是本地方法,并且为final方法,无法被重写。

2)调用某个对象的wait()方法能让当前线程阻塞,并且当前线程必须拥有此对象的monitor(即锁)

3)调用某个对象的notify()方法能够唤醒一个正在等待这个对象的monitor的线程,如果有多个线程都在等待这个对象的monitor,则只能唤醒其中一个线程;

4)调用notifyAll()方法能够唤醒所有正在等待这个对象的monitor的线程;

(三)Lock接口,ReentrantLock、Condition说明

fdea0861c50d7c66acca2fac4d6d6416.png

3.1重要概念:可重入性

可重入性描述这样的一个问题:一个线程在持有一个锁的时候,它内部能否再次(多次)申请该锁。如果一个线程已经获得了锁,其内部还可以多次申请该锁成功。那么我们就称该锁为可重入锁。通过以下伪代码说明:

1 voidmethodA(){2 lock.lock(); //获取锁

3 methodB();4 lock.unlock() //释放锁

5 }6

7 voidmethodB(){8 lock.lock(); //获取锁9 //其他业务

10 lock.unlock();//释放锁

11 }

可重入锁可以理解为锁的一个标识。该标识具备计数器功能。标识的初始值为0,表示当前锁没有被任何线程持有。每次线程获得一个可重入锁的时候,该锁的计数器就被加1。每次一个线程释放该所的时候,该锁的计数器就减1。前提是:当前线程已经获得了该锁,是在线程的内部出现再次获取锁的场景

3.2 ReentrantLock实现说明

该demo模拟电影院的售票情况,tickets总票数。开启了10个窗口售票,售完为止

1 public class ReentrantLockDemo01 implementsRunnable {2

3 private Lock lock = newReentrantLock();4

5 private int tickets = 200;6

7 @Override8 public voidrun() {9 while (true) {10 lock.lock(); //获取锁

11 try{12 if (tickets > 0) {13 TimeUnit.MILLISECONDS.sleep(100);14 System.out.println(Thread.currentThread().getName() + " " + tickets--);15 } else{16 break;17 }18 } catch(InterruptedException e) {19 e.printStackTrace();20 } finally{21 lock.unlock(); //释放所

22 }23 }24 }25

26 public static voidmain(String[] args) {27 ReentrantLockDemo01 reentrantLockDemo = newReentrantLockDemo01();28 for (int i = 0; i < 10; i++) {29 Thread thread = new Thread(reentrantLockDemo, "thread" +i);30 thread.start();31 }32 }33 }

3.3lockInterruptibly()方法说明

从Lock的源码可以看出:lockInterruptibly() 抛出中断异常

1 void lockInterruptibly() throws InterruptedException;

3.4 tryLock(),tryLock(long time, TimeUnit unit)方法说明

tryLock()方法立刻返回当前获取情况。

tryLock(long time, TimeUnit unit)等待一定的时间,返回获取情况

1 public class ReentrantLockDemo03 implementsRunnable {2

3 private ReentrantLock lock = newReentrantLock();4

5 @Override6 public voidrun() {7 try{8 if (lock.tryLock(2, TimeUnit.SECONDS)) {9 System.out.println(Thread.currentThread().getName() + " 获取当前lock锁");10 TimeUnit.SECONDS.sleep(4);11 } else{12 System.out.println(Thread.currentThread().getName()+ " 获取锁失败");13 }14 } catch(InterruptedException e) {15 e.printStackTrace();16 } finally{17 if(lock.isHeldByCurrentThread()) {18 lock.unlock();19 }20 }21 }22

23

24 public static voidmain(String[] args) {25 ReentrantLockDemo03 reentrantLockDemo = newReentrantLockDemo03();26 Thread thread01 = new Thread(reentrantLockDemo, "thread01");27 Thread thread02 = new Thread(reentrantLockDemo, "thread02");28 thread01.start();29 thread02.start();30 }

3.5 newCondition() 方法说明

目前只是对newCondition()使用方式进行说明,没有深入的分析Condition()的实现源码。

Condition的作用是对锁进行更精确的控制。Condition中的await()方法相当于Object的wait()方法,Condition中的signal()方法相当于Object的notify()方法,Condition中的signalAll()相当于Object的notifyAll()方法。不同的是,Object中的wait(),notify(),notifyAll()方法是和”同步锁”(synchronized关键字)捆绑使用的;而Condition是需要与”互斥锁”/”共享锁”捆绑使用的。

3.6 Condition

Condition是在java 1.5中才出现的,它用来替代传统的Object的wait()、notify()实现线程间的协作,相比使用Object的wait()、notify(),使用Condition1的await()、signal()这种方式实现线程间协作更加安全和高效。因此通常来说比较推荐使用Condition,在阻塞队列那一篇博文中就讲述到了,阻塞队列实际上是使用了Condition来模拟线程间协作。

Condition是个接口,基本的方法就是await()和signal()方法;

Condition依赖于Lock接口,生成一个Condition的基本代码是lock.newCondition()

调用Condition的await()和signal()方法,都必须在lock保护之内,就是说必须在lock.lock()和lock.unlock之间才可以使用

Conditon中的await()对应Object的wait();

Condition中的signal()对应Object的notify();

Condition中的signalAll()对应Object的notifyAll()。

(四)两种方式的多线程通信的实现

1 packagecn.csrc.base.cpu;2 importjava.util.concurrent.locks.Condition;3 importjava.util.concurrent.locks.ReentrantLock;4 /**

5 *6 *功能说明:线程间通信的两种方式 (1)Object (2)ReentrantLock7 *@author:zsq8 *create date:2019年7月2日 下午4:23:419 *修改人 修改时间 修改描述10 *Copyright11 */

12 public classOddEvenPrinter {13

14 //第一种方法 object作为锁

15 private final Object obj=newObject();16

17 //第二种方法

18 private final ReentrantLock lock=newReentrantLock();19 private final Condition condition=lock.newCondition();20

21 private intlimit;22 private volatile intcount;23

24 public OddEvenPrinter(int limit,intcount){25 this.limit=limit;26 this.count=count;27 }28

29 //Object锁

30 public voidmyPrint1(){31 synchronized(obj) {32 while(count

44 //ReentrantLock 重入锁

45 public voidmyPrint2(){46 //一进入就加锁

47 lock.lock();48 try{49 while(count

52 }53 } catch(Exception e) {54 e.printStackTrace();55 }finally{56 //最后释放锁

57 lock.unlock();58 }59 }60

61 public static void main(String[] args) throwsInterruptedException {62 OddEvenPrinter print = new OddEvenPrinter(10, 0);63 System.err.println("-----------第一种方法 Object-----------");64 Thread thread1 = new Thread(print::myPrint1, "thread-A");65 Thread thread2 = new Thread(print::myPrint1, "thread-B");66 thread1.start();67 thread2.start();68 Thread.sleep(1000);69

70 System.err.println("-----------第二种方法 lock-----------");71 Thread thread3 = new Thread(print::myPrint2, "thread-C");72 Thread thread4 = new Thread(print::myPrint2, "thread-D");73 thread3.start();74 thread4.start();75 Thread.sleep(1000);76 }77

78 }

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值