java 多线程 Thread 锁ReentrantLock;Condition等待与通知;公平锁
1,介绍:
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
在JAVA的多线程编程中,我们可以使用synchronized关键字来实现线程之间的同步互斥,但是JDK1.5中新增了ReentrantLock类同样也能达到效果,并且功能上更加强大。比如有嗅探锁定功能,多路分支通知功能,并且使用上比synchronized更加灵活。
2,基本使用:
使用lock()方法上锁,使用unlock()方法解锁
效果:
- 加锁和解锁之间的代码块,多个线程运行变串行
代码示例:
import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReentrantLock; /** * @ClassName LockReentrantLockExample * @projectName: object1 * @author: Zhangmingda * @description: XXX * date: 2021/4/24. */ public class LockReentrantLockExample { public static void main(String[] args) { Lock lock = new ReentrantLock(); Runnable r = () -> { String tName = Thread.currentThread().getName(); System.out.println("子线程运行"); lock.lock(); System.out.println(tName + "准备睡觉了"); try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(tName + "睡醒了"); lock.unlock(); }; Thread thread = new Thread(r,"child1"); Thread thread1 = new Thread(r,"child2"); Thread thread2 = new Thread(r,"child3"); thread.start(); thread1.start(); thread2.start(); } }
3、等待/通知 机制的实现:
3.1 Conditiond对象的await方法实现等待,signal方法实现通知
import java.util.concurrent.locks.Condition; import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReentrantLock; /** * @ClassName LockReentrantLockCondition * @projectName: object1 * @author: Zhangmingda * @description: XXX * date: 2021/4/25. */ public class LockReentrantLockCondition { public static void main(String[] args) { //锁 Lock lock = new ReentrantLock(); //暂停唤醒工具 Condition condition = lock.newCondition(); //子线程本地变量 ThreadLocal<String> tName = new ThreadLocal<>(){ @Override protected String initialValue() { return Thread.currentThread().getName(); } }; Runnable r = new Runnable() { @Override public void run() { System.out.println(tName.get() + "开始运行!"); lock.lock(); try { Thread.sleep(1000); System.out.println(tName.get() + "暂停"); condition.await(); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(tName.get() + "运行结束"); lock.unlock(); } }; Thread thread = new Thread(r,"A"); Thread thread1 = new Thread(r,"B"); Thread thread2 = new Thread(r,"C"); Thread call = new Thread(){ @Override public void run() { try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } lock.lock(); condition.signalAll(); lock.unlock(); } }; thread.start(); thread1.start(); thread2.start(); call.start(); } }
效果:锁依次被ABC线程获取到,分别进入await()状态。最后call线程才获取到ABC抛出的锁,
3.2等待通知案例:做馒头,吃馒头,相对优化版
- 做馒头多线程几乎并发,做馒头耗时并发sleep;
- 吃馒头几乎并发,sleep 并发执行 lock.unlock();在 sleep外
import java.util.LinkedList; import java.util.Random; import java.util.concurrent.locks.Condition; import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReentrantLock; /** * @ClassName ReentrantLockConditionMantou * @projectName: object1 * @author: Zhangmingda * @description: XXX * date: 2021/4/25. */ public class ReentrantLockConditionMantou { private static void reentrantLockCondition(){ LinkedList<String> mantous = new LinkedList<>(); Lock lock = new ReentrantLock(); Condition fuwuyuan = lock.newCondition(); Runnable produce = () -> { String threadName = Thread.currentThread().getName(); while (true) { lock.lock(); if (mantous.size() >= 10 ){ fuwuyuan.signalAll(); //有可能被另一个厨师实例获取到 try { Thread.sleep(100); //两个厨师,避免厨师之间相互获取到锁,给点时间让食客获取到锁 System.out.println(threadName + ": 馒头做够了.........................你们来吃吧"); fuwuyuan.await(); } catch (InterruptedException e) { e.printStackTrace(); } lock.unlock(); } else { mantous.add("馒头"); System.out.println(threadName + ",我生产了一个馒头,当前的馒头数量是" + mantous.size()); lock.unlock(); try { Thread.sleep(1000); //做馒头花时间 } catch (InterruptedException e) { e.printStackTrace(); } } } }; Runnable customer = () -> { String threadName = Thread.currentThread().getName(); Random random = new Random(); while (true) { //吃馒头的数量 int buyMantou = Math.abs(random.nextInt()) % 5 + 1; //获取锁 lock.lock(); if (mantous.size() < buyMantou) { fuwuyuan.signalAll(); System.out.println("\033[31;1m" + threadName + "想吃" + buyMantou + "只有" +mantous.size() + "个了,快做馒头吧\033[0m"); try { //稍微歇一歇 Thread.sleep(300); //给点机会上厨师获取到锁,避免其他食客获取到锁 fuwuyuan.await(); lock.unlock(); } catch (InterruptedException e) { e.printStackTrace(); } } else { //吃馒头 for (int i = 0; i < buyMantou; i++) { if(mantous.poll() == null){ System.out.println(threadName + "吃了个空....."); } } System.out.println(threadName + ",我吃了" + buyMantou + "个馒头,当前馒头的数量是:" + mantous.size()); lock.unlock(); try { Thread.sleep(2000); } catch (InterruptedException e) { e.printStackTrace(); } } } }; Thread thread = new Thread(produce,"厨师1"); Thread thread1 = new Thread(produce,"厨师2"); Thread thread2 = new Thread(customer,"饭桶1"); Thread thread3 = new Thread(customer,"饭桶2"); Thread thread4 = new Thread(customer,"饭桶3"); thread.start(); thread1.start(); thread2.start(); thread3.start(); thread4.start(); } public static void main(String[] args) { reentrantLockCondition(); } }
"C:\Program Files\JetBrains\IntelliJ IDEA Community Edition 2019.3\jbr\bin\java.exe" "-javaagent:C:\Program Files\JetBrains\IntelliJ IDEA Community Edition 2019.3\lib\idea_rt.jar=54462:C:\Program Files\JetBrains\IntelliJ IDEA Community Edition 2019.3\bin" -Dfile.encoding=UTF-8 -classpath D:\JavaStudy2\object1\out\production\多线程 ReentrantLockConditionMantou 厨师1,我生产了一个馒头,当前的馒头数量是1 厨师2,我生产了一个馒头,当前的馒头数量是2 饭桶3,我吃了2个馒头,当前馒头的数量是:0 饭桶1想吃4只有0个了,快做馒头吧 饭桶2想吃3只有0个了,快做馒头吧 饭桶1想吃5只有0个了,快做馒头吧 饭桶2想吃4只有0个了,快做馒头吧 厨师1,我生产了一个馒头,当前的馒头数量是1 厨师2,我生产了一个馒头,当前的馒头数量是2 饭桶1想吃4只有2个了,快做馒头吧 饭桶2想吃5只有2个了,快做馒头吧 饭桶1,我吃了1个馒头,当前馒头的数量是:1 饭桶3,我吃了1个馒头,当前馒头的数量是:0 厨师2,我生产了一个馒头,当前的馒头数量是1 厨师1,我生产了一个馒头,当前的馒头数量是2 厨师1,我生产了一个馒头,当前的馒头数量是3 厨师2,我生产了一个馒头,当前的馒头数量是4 饭桶1,我吃了3个馒头,当前馒头的数量是:1 饭桶3想吃3只有1个了,快做馒头吧 饭桶2想吃3只有1个了,快做馒头吧 厨师1,我生产了一个馒头,当前的馒头数量是2 厨师2,我生产了一个馒头,当前的馒头数量是3 饭桶3想吃5只有3个了,快做馒头吧 饭桶2想吃4只有3个了,快做馒头吧 饭桶3,我吃了1个馒头,当前馒头的数量是:2 厨师1,我生产了一个馒头,当前的馒头数量是3 厨师2,我生产了一个馒头,当前的馒头数量是4 饭桶1,我吃了2个馒头,当前馒头的数量是:2 厨师1,我生产了一个馒头,当前的馒头数量是3 厨师2,我生产了一个馒头,当前的馒头数量是4 饭桶3想吃5只有4个了,快做馒头吧 饭桶2,我吃了4个馒头,当前馒头的数量是:0 厨师2,我生产了一个馒头,当前的馒头数量是1 厨师1,我生产了一个馒头,当前的馒头数量是2 饭桶1想吃4只有2个了,快做馒头吧 饭桶3想吃5只有2个了,快做馒头吧 饭桶1,我吃了2个馒头,当前馒头的数量是:0 厨师2,我生产了一个馒头,当前的馒头数量是1 厨师1,我生产了一个馒头,当前的馒头数量是2 饭桶2想吃5只有2个了,快做馒头吧 饭桶3想吃4只有2个了,快做馒头吧 厨师2,我生产了一个馒头,当前的馒头数量是3 厨师1,我生产了一个馒头,当前的馒头数量是4 饭桶2,我吃了1个馒头,当前馒头的数量是:3 饭桶1,我吃了3个馒头,当前馒头的数量是:0 厨师2,我生产了一个馒头,当前的馒头数量是1 厨师1,我生产了一个馒头,当前的馒头数量是2 饭桶2想吃5只有2个了,快做馒头吧 饭桶3想吃3只有2个了,快做馒头吧 厨师1,我生产了一个馒头,当前的馒头数量是3 厨师2,我生产了一个馒头,当前的馒头数量是4 饭桶2,我吃了1个馒头,当前馒头的数量是:3 饭桶1,我吃了3个馒头,当前馒头的数量是:0 厨师1,我生产了一个馒头,当前的馒头数量是1 厨师2,我生产了一个馒头,当前的馒头数量是2 厨师2,我生产了一个馒头,当前的馒头数量是3 饭桶2,我吃了1个馒头,当前馒头的数量是:2 厨师1,我生产了一个馒头,当前的馒头数量是3 饭桶1想吃5只有3个了,快做馒头吧 饭桶3,我吃了1个馒头,当前馒头的数量是:2 厨师1,我生产了一个馒头,当前的馒头数量是3 厨师2,我生产了一个馒头,当前的馒头数量是4 饭桶2,我吃了3个馒头,当前馒头的数量是:1 厨师2,我生产了一个馒头,当前的馒头数量是2 厨师1,我生产了一个馒头,当前的馒头数量是3 饭桶3,我吃了2个馒头,当前馒头的数量是:1 厨师1,我生产了一个馒头,当前的馒头数量是2 厨师2,我生产了一个馒头,当前的馒头数量是3 饭桶2,我吃了2个馒头,当前馒头的数量是:1 厨师1,我生产了一个馒头,当前的馒头数量是2 厨师2,我生产了一个馒头,当前的馒头数量是3 饭桶3想吃5只有3个了,快做馒头吧 饭桶1想吃5只有3个了,快做馒头吧 饭桶3,我吃了2个馒头,当前馒头的数量是:1 厨师1,我生产了一个馒头,当前的馒头数量是2 厨师2,我生产了一个馒头,当前的馒头数量是3 饭桶2想吃4只有3个了,快做馒头吧 饭桶1,我吃了3个馒头,当前馒头的数量是:0 厨师2,我生产了一个馒头,当前的馒头数量是1 厨师1,我生产了一个馒头,当前的馒头数量是2 饭桶3想吃5只有2个了,快做馒头吧 饭桶2,我吃了1个馒头,当前馒头的数量是:1 厨师1,我生产了一个馒头,当前的馒头数量是2 厨师2,我生产了一个馒头,当前的馒头数量是3 厨师1,我生产了一个馒头,当前的馒头数量是4 厨师2,我生产了一个馒头,当前的馒头数量是5 饭桶1,我吃了5个馒头,当前馒头的数量是:0 饭桶2想吃4只有0个了,快做馒头吧 饭桶3想吃3只有0个了,快做馒头吧 厨师2,我生产了一个馒头,当前的馒头数量是1 厨师1,我生产了一个馒头,当前的馒头数量是2 饭桶2,我吃了2个馒头,当前馒头的数量是:0 饭桶1想吃1只有0个了,快做馒头吧 饭桶3想吃2只有0个了,快做馒头吧 饭桶1想吃1只有0个了,快做馒头吧 厨师2,我生产了一个馒头,当前的馒头数量是1 厨师1,我生产了一个馒头,当前的馒头数量是2 饭桶3,我吃了1个馒头,当前馒头的数量是:1 饭桶2,我吃了1个馒头,当前馒头的数量是:0 厨师2,我生产了一个馒头,当前的馒头数量是1 厨师1,我生产了一个馒头,当前的馒头数量是2 饭桶3想吃4只有2个了,快做馒头吧 饭桶1,我吃了2个馒头,当前馒头的数量是:0 厨师2,我生产了一个馒头,当前的馒头数量是1 厨师1,我生产了一个馒头,当前的馒头数量是2 饭桶2想吃3只有2个了,快做馒头吧 饭桶3想吃3只有2个了,快做馒头吧 饭桶2,我吃了2个馒头,当前馒头的数量是:0 厨师2,我生产了一个馒头,当前的馒头数量是1 厨师1,我生产了一个馒头,当前的馒头数量是2 饭桶1想吃5只有2个了,快做馒头吧 饭桶3想吃5只有2个了,快做馒头吧 厨师2,我生产了一个馒头,当前的馒头数量是3 厨师1,我生产了一个馒头,当前的馒头数量是4 饭桶1想吃5只有4个了,快做馒头吧 饭桶3,我吃了3个馒头,当前馒头的数量是:1 饭桶2想吃5只有1个了,快做馒头吧 饭桶1想吃3只有1个了,快做馒头吧 Process finished with exit code -1
公平锁和非公平锁:
锁Lock分为公平锁和非公平锁,公平锁表示线程获取锁的顺序是按照线程加锁的顺序来分配的,也就是先进先出的顺序。而非公平锁就是一种获取锁的抢占机制,是随机获取的,和公平锁不一样的就是先来的不一定先得到锁,这个方式可能造成某些线程一直拿不到锁。如果我们用synchronized的方式我们没有办法使用公平锁。
创建公平锁的办法是在new ReentrantLock的时候加一个参数true.
new ReentrantLock(true)
posted on 2021-04-24 22:47 zhangmingda 阅读(146) 评论(0) 编辑 收藏 举报