In addition to Weibo, there is also WeChat
Please pay attention
WeChat public account
Shulou
2025-01-19 Update From: SLTechnology News&Howtos shulou NAV: SLTechnology News&Howtos > Internet Technology >
Share
Shulou(Shulou.com)06/01 Report--
This article focuses on "how to use monitor and ReentrantLock". Interested friends may wish to have a look at it. The method introduced in this paper is simple, fast and practical. Let the editor take you to learn how to use monitor and ReentrantLock.
First implement a code that uses built-in locks to coordinate two threads. Thread coordination through internal locks through the synchronized keyword actually helps us hide the concept of conditional queues. Roughly speaking, an internal lock is a reentrant mutex. The following code is an implementation that makes use of internal locks.
For more information, please see the notes:
Public class FooBarByMonitor {private int n
Public FooBarByMonitor (int n) {this.n = n;}
Private final Object lock = new Object (); / / _ because you cannot modify the front of the method of the topic, you cannot use the default monitor of the current object. Create an object to take advantage of its monitor.
Private volatile boolean isFooTurn = true; / / _ defines a boolean variable that represents two mutually exclusive states.
Public void foo (Runnable printFoo) throws InterruptedException {for (int I = 0; I
< n; i++) { synchronized (lock) { while (!isFooTurn) lock.wait(); //_ 如果不该打印foo则阻塞(把当前线程放到lock的等待队列),等待通知。第一次是可打印的。 printFoo.run(); isFooTurn = false; //_ 更改到可以打印bar的状态。 lock.notify(); //_ 因为只有两个线程,所以notify是可以的,否则应使用notifyAll。 } } } public void bar(Runnable printBar) throws InterruptedException { for (int i = 0; i < n; i++) { synchronized (lock) { while (isFooTurn) lock.wait(); //_ 如果不该打印bar则阻塞,等待通知。 printBar.run(); isFooTurn = true; //_ 更改到可以打印foo的状态。 lock.notify(); //_ 唤醒其它等待的线程。 } } }} 前面文章《条件队列是个线程的队列》里提到Lock是内部锁的显示化,Condition是内部锁条件队列的显示化。对比下面和上面的代码,应该可以体会到这一点。通过由Lock对象针对不同"条件谓词"定义出不同等待队列,可以做得比使用内部锁提供的多个条件谓词共享一个等待队列的模式更高效地进行线程协调。所谓线程协调就是安排线程适当的阻塞、唤醒、运行的切换而已。 最开始学习"条件队列"时,我对"条件"这个词感到莫名其妙。为什么不叫'等待队列'?'条件'从何而来? 其实这要从 谓词--Predicate 说起,可参考wiki定义。简单的说"谓词"就是指那些返回真或假的表达式。而条件--Condition就是某事成真或假的前提。我们常用变量表示conditon的状态,这就是condition variable。 条件谓词--Conditon Predicate,翻译成人话就是最终用一个变量得出真、假的判断。 那这跟多线程编程又有什么关系呢?关系还挺深的。并发编程的核心是协调线程的运行,就是有时候一些线程可以运行而另一些线程要暂停下来。那么根据什么来阻塞、唤醒线程呢?这就要根据你实际业务里的逻辑来决定,这个逻辑运算的结果就是个boolean值。这个逻辑最终体现在condition variable、体现在Conditon Predicate上。对于下面这段轮流打印foobar的代码,决定线程阻塞还是运行的条件就是"该打印foo了吗?",我们用isFooTurn这个变量来表示。对于阻塞队列的添加、删除操作来说,对应的条件变量就应该能反应这个队列的满、空状态。多线程的协调就是合理的基于条件变量改变线程自身的状态以及改变条件变量的状态来完成的。 回到"条件队列"这词上来就容易了,条件队列里装的都是等待条件发生变化的线程。希望到此你跟我一样对"条件队列"这个词再没有违和感了。:) 知识点细节见注释: public class FooBarByLock { private int n; public FooBarByLock(int n) { this.n = n; } //_ 这里相对使用Semaphore的版本多出一个状态变量表示 应该打印foo还是bar。 //_ 在Semaphore的版本里我们没有多定义一个变量是因为 对foo信号量初始化为1,即实现了先打印1。 //_ 另外由于信号量交替acquire,release的特性保证了不需要额外定义一个状态变量。 //_ 同时,这个变量也是用于表达下面两个条件队列对应'条件谓词'的关键。 private volatile boolean isFooTurn = true; private final Lock lock = new ReentrantLock(); private final Condition fooCondition = lock.newCondition(); //_ 对应条件谓词 'isFooTurn == true' private final Condition barCondition = lock.newCondition(); //_ 对应条件谓词 'isFooTurn == false' public void foo(Runnable printFoo) throws InterruptedException { for (int i = 0; i < n; i++) { lock.lock(); try { //_ 虽然在这道例题里可以使用if,但是如果有多个线程可以更改这个用于表达条件谓词的变量isFooTurn就会出现问题。 while (!isFooTurn) { //_ 虽然使用针对此题是没问题的,作为定式这里直接使用循环。 fooCondition.await(); //_ 等待打印foo的条件谓词成立。因为isFooTurn初始化为true,所以第一轮不阻塞。 } printFoo.run(); isFooTurn = false; //_ 更改条件谓词,使另个线程可以继续。 barCondition.signal(); //_ 通知bar的条件队列,可以打印了。 } finally { lock.unlock(); } } } public void bar(Runnable printBar) throws InterruptedException { for (int i = 0; i < n; i++) { lock.lock(); try { while (isFooTurn) { barCondition.await(); //_ 阻塞。等待打印bar的条件谓词'isFooTurn == false'成立 } printBar.run(); isFooTurn = true; fooCondition.signal(); } finally { lock.unlock(); } } } public static void main(String[] args) { FooBarByLock foobar = new FooBarByLock(20); new Thread(() ->{try {foobar.foo (()-> System.out.print ("foo"));} catch (InterruptedException e) {e.printStackTrace ();}}) .start ()
New Thread (()-> {try {foobar.bar (()-> System.out.print ("bar"));} catch (InterruptedException e) {e.printStackTrace ();}}). Start ();}} at this point, I believe you have a deeper understanding of "how to use monitor and ReentrantLock". You might as well do it in practice! Here is the website, more related content can enter the relevant channels to inquire, follow us, continue to learn!
Welcome to subscribe "Shulou Technology Information " to get latest news, interesting things and hot topics in the IT industry, and controls the hottest and latest Internet news, technology news and IT industry trends.
Views: 0
*The comments in the above article only represent the author's personal views and do not represent the views and positions of this website. If you have more insights, please feel free to contribute and share.
Continue with the installation of the previous hadoop.First, install zookooper1. Decompress zookoope
"Every 5-10 years, there's a rare product, a really special, very unusual product that's the most un
© 2024 shulou.com SLNews company. All rights reserved.