【java多线程编程核心技术】4.Lock的使用-笔记总结
来源:互联网 发布:什么是qq群淘宝客 编辑:程序博客网 时间:2024/05/17 09:34
使用ReentrantLock类
一个可重入的互斥锁 Lock,它具有与使用 synchronized方法和语句所访问的隐式监视器锁相同的一些基本行为和语义,并且在扩充功能上也更强大,比如具有嗅探锁定、多路分支通知等功能。
使用ReentranLock实现同步
package service;import java.util.concurrent.locks.Lock;import java.util.concurrent.locks.ReentrantLock;public class MyService { private Lock lock = new ReentrantLock(); public void testMethod() { lock.lock(); for (int i = 0; i < 5; i++) { System.out.println("ThreadName=" + Thread.currentThread().getName() + (" " + (i + 1))); } lock.unlock(); }}......省略代码
与synchronized用法相似,只是多出来一个解锁(lock.unlock())的过程
使用Condition实现等待/通知
与上一章通过wait()和notify()/notifyAll()类似,ReentrantLock类也可以实现同样的功能,但需要借助于Condition对象(await()与signal/signalAll())
ReentrantLock类结合Condition类可以实现“选择性通知”(notify()进行通知时,被通知的线程是由JVM随机选择的)
package extthread;import service.MyService;public class ThreadA extends Thread { private MyService service; public ThreadA(MyService service) { super(); this.service = service; } @Override public void run() { service.await(); }}package service;import java.util.concurrent.locks.Condition;import java.util.concurrent.locks.Lock;import java.util.concurrent.locks.ReentrantLock;public class MyService { private Lock lock = new ReentrantLock(); public Condition condition = lock.newCondition(); public void await() { try { lock.lock(); System.out.println(" await时间为" + System.currentTimeMillis()); condition.await(); } catch (InterruptedException e) { e.printStackTrace(); } finally { lock.unlock(); } } public void signal() { try { lock.lock(); System.out.println("signal时间为" + System.currentTimeMillis()); condition.signal(); } finally { lock.unlock(); } }}package test;import service.MyService;import extthread.ThreadA;public class Run { public static void main(String[] args) throws InterruptedException { MyService service = new MyService(); ThreadA a = new ThreadA(service); a.start(); Thread.sleep(3000); service.signal(); }}输出结果: await时间为1511258842692signal时间为1511258845691
使用多个Condition实现通知部分线程
package extthread;import service.MyService;public class ThreadA extends Thread { private MyService service; public ThreadA(MyService service) { super(); this.service = service; } @Override public void run() { service.awaitA(); }}package extthread;import service.MyService;public class ThreadB extends Thread { private MyService service; public ThreadB(MyService service) { super(); this.service = service; } @Override public void run() { service.awaitB(); }}package service;import java.util.concurrent.locks.Condition;import java.util.concurrent.locks.Lock;import java.util.concurrent.locks.ReentrantLock;public class MyService { private Lock lock = new ReentrantLock(); public Condition conditionA = lock.newCondition(); public Condition conditionB = lock.newCondition(); public void awaitA() { try { lock.lock(); System.out.println("begin awaitA时间为" + System.currentTimeMillis() + " ThreadName=" + Thread.currentThread().getName()); conditionA.await(); System.out.println(" end awaitA时间为" + System.currentTimeMillis() + " ThreadName=" + Thread.currentThread().getName()); } catch (InterruptedException e) { e.printStackTrace(); } finally { lock.unlock(); } } public void awaitB() { try { lock.lock(); System.out.println("begin awaitB时间为" + System.currentTimeMillis() + " ThreadName=" + Thread.currentThread().getName()); conditionB.await(); System.out.println(" end awaitB时间为" + System.currentTimeMillis() + " ThreadName=" + Thread.currentThread().getName()); } catch (InterruptedException e) { e.printStackTrace(); } finally { lock.unlock(); } } public void signalAll_A() { try { lock.lock(); System.out.println(" signalAll_A时间为" + System.currentTimeMillis() + " ThreadName=" + Thread.currentThread().getName()); conditionA.signalAll(); } finally { lock.unlock(); } } public void signalAll_B() { try { lock.lock(); System.out.println(" signalAll_B时间为" + System.currentTimeMillis() + " ThreadName=" + Thread.currentThread().getName()); conditionB.signalAll(); } finally { lock.unlock(); } }}package test;import service.MyService;import extthread.ThreadA;import extthread.ThreadB;public class Run { public static void main(String[] args) throws InterruptedException { MyService service = new MyService(); ThreadA a = new ThreadA(service); a.setName("A"); a.start(); ThreadB b = new ThreadB(service); b.setName("B"); b.start(); Thread.sleep(3000); service.signalAll_A(); }}输出结果:(只通知了A)begin awaitA时间为1511258966784 ThreadName=Abegin awaitB时间为1511258966785 ThreadName=B signalAll_A时间为1511258969785 ThreadName=main end awaitA时间为1511258969785 ThreadName=A
使用ReentrantLock对象可以唤醒指定种类的线程,这是控制部分线程行为的方便方式。
实现生产者/消费者模式:多对多交替打印
package extthread;import service.MyService;public class MyThreadA extends Thread { private MyService myService; public MyThreadA(MyService myService) { super(); this.myService = myService; } @Override public void run() { for (int i = 0; i < Integer.MAX_VALUE; i++) { myService.set(); } }}package extthread;import service.MyService;public class MyThreadB extends Thread { private MyService myService; public MyThreadB(MyService myService) { super(); this.myService = myService; } @Override public void run() { for (int i = 0; i < Integer.MAX_VALUE; i++) { myService.get(); } }}package service;import java.util.concurrent.locks.Condition;import java.util.concurrent.locks.ReentrantLock;public class MyService { private ReentrantLock lock = new ReentrantLock(); private Condition condition = lock.newCondition(); private boolean hasValue = false; public void set() { try { lock.lock(); while (hasValue == true) { System.out.println("有可能★★连续"); condition.await(); } System.out.println("打印★"); hasValue = true; condition.signalAll(); } catch (InterruptedException e) { e.printStackTrace(); } finally { lock.unlock(); } } public void get() { try { lock.lock(); while (hasValue == false) { System.out.println("有可能☆☆连续"); condition.await(); } System.out.println("打印☆"); hasValue = false; condition.signalAll(); } catch (InterruptedException e) { e.printStackTrace(); } finally { lock.unlock(); } }}package test;import service.MyService;import extthread.MyThreadA;import extthread.MyThreadB;public class Run { public static void main(String[] args) throws InterruptedException { MyService service = new MyService(); MyThreadA[] threadA = new MyThreadA[10]; MyThreadB[] threadB = new MyThreadB[10]; for (int i = 0; i < 10; i++) { threadA[i] = new MyThreadA(service); threadB[i] = new MyThreadB(service); threadA[i].start(); threadB[i].start(); } }}输出结果:有可能★★连续有可能★★连续打印☆有可能☆☆连续有可能☆☆连续有可能☆☆连续打印★有可能★★连续打印☆.......
出现连续★★或者☆☆是因为signalAll()唤醒的同类争抢到了锁,这也是**只使用一个**condition的缺点吧。
公平锁与非公平锁
锁Lock分为“公平锁”和“非公平锁”。
公平锁:表示线程获取锁的顺序是按照线程加锁的顺序来分配,即先来先得的FIFO顺序(也可以说成优先选择等待时间最长的线程)
非公平锁:是一种获取锁的抢占机制,是随机获取锁。
设置方法:lock=new ReentrantLock(true)/lock=new ReentrantLock(false) 默认是false,不公平
常用API介绍
getHoldCount() 查询当前线程保持此锁定的个数,也就是调用 lock() 的方法//lock.getHoldCount(); intgetQueueLength() 返回正等待获取此锁定的线程估计数//lock.getQueueLength(); intgetWaitQueueLength() 返回等待与此锁定相关的给定条件 Condition 的线程估计数//lock.getWaitQueueLength(newCondition) int 个人感觉有点类似于上一章提到的“阻塞队列”hasQueuedThread() 查询指定的线程是否正在等待获取此锁定//lock.hasQueuedThread(threadA); booleanhasQueuedThreads() 查询是否有线程正在等待获取此锁定//lock.hasQueuedThreads; booleanhasWaiters() 查询是否有线程正在等待与此锁定有关的 condition 条件//lock.hasWaiters(newCondition); booleanisFair() 判断是否是公平锁//lock.isFair(); booleanisHeldByCurrentThread() 查询当前线程是否保持此锁定//lock.isHeldByCurrentThread(); booleanisLocked() 查询此锁定是否由任意线程保持//lock.isLocked(); booleanlockInterruptibly() 如果当前线程未被中断,则获取锁定,如果已经被中断则出现异常//lock.lockInterruptibly(); voidtryLock() 仅在调用时锁定未被另一个线程保持的情况下,才获取该锁定(拿不到,立即返回)//lock.tryLock(); booleantryLock(long time, TimeUtil util) 如果锁定在给定的等待时间内没有被另一个线程保持,且当前线程未被中断,则获取该锁定。//lock.tryLock(3,TimeUtil.SECONDS); booleanawaitUninterruptibly():等待释放锁而且在线程被打断时interrupt()不会抛出异常//condition.awaitUninterruptibly() awaitUntil():如果在对应的时间内未被唤醒,则在对应时间结束后自动唤醒自己用法: Calendar calendarRef = Calendar.getInstance(); calendarRef.add(Calendar.SECOND, 10); lock.lock(); condition.awaitUntil(calendarRef.getTime());
述API常用配套使用:
public ReentrantLock lock = new ReentrantLock(); public void waitMethod() { try { if (lock.tryLock(3, TimeUnit.SECONDS)) { //用法 System.out.println(" " + Thread.currentThread().getName() + "获得锁的时间:" + System.currentTimeMillis()); Thread.sleep(10000); } else { System.out.println(" " + Thread.currentThread().getName() + "没有获得锁"); } } catch (InterruptedException e) { e.printStackTrace(); } finally { if (lock.isHeldByCurrentThread()) { //用法: lock.unlock(); } } }}
使用Condition实现顺序执行
package finaltools;public class F { volatile public static int nextPrintWho = 1;}package test.run;import java.util.concurrent.locks.Condition;import java.util.concurrent.locks.ReentrantLock;public class Run { volatile private static int nextPrintWho = 1; private static ReentrantLock lock = new ReentrantLock(); final private static Condition conditionA = lock.newCondition(); final private static Condition conditionB = lock.newCondition(); final private static Condition conditionC = lock.newCondition(); public static void main(String[] args) { Thread threadA = new Thread() { public void run() { try { lock.lock(); while (nextPrintWho != 1) { conditionA.await(); } for (int i = 0; i < 3; i++) { System.out.println("ThreadA " + (i + 1)); } nextPrintWho = 2; conditionB.signalAll(); } catch (InterruptedException e) { e.printStackTrace(); } finally { lock.unlock(); } } }; Thread threadB = new Thread() { public void run() { try { lock.lock(); while (nextPrintWho != 2) { conditionB.await(); } for (int i = 0; i < 3; i++) { System.out.println("ThreadB " + (i + 1)); } nextPrintWho = 3; conditionC.signalAll(); } catch (InterruptedException e) { e.printStackTrace(); } finally { lock.unlock(); } } }; Thread threadC = new Thread() { public void run() { try { lock.lock(); while (nextPrintWho != 3) { conditionC.await(); } for (int i = 0; i < 3; i++) { System.out.println("ThreadC " + (i + 1)); } nextPrintWho = 1; conditionA.signalAll(); } catch (InterruptedException e) { e.printStackTrace(); } finally { lock.unlock(); } } }; Thread[] aArray = new Thread[5]; Thread[] bArray = new Thread[5]; Thread[] cArray = new Thread[5]; for (int i = 0; i < 5; i++) { aArray[i] = new Thread(threadA); bArray[i] = new Thread(threadB); cArray[i] = new Thread(threadC); aArray[i].start(); bArray[i].start(); cArray[i].start(); } }}输出结果:ThreadA 1ThreadA 2ThreadA 3ThreadB 1ThreadB 2ThreadB 3ThreadC 1ThreadC 2ThreadC 3.......
使用ReentrantReadWriteLock类
读写锁ReentrantReadWriteLock类,表示有2个锁,一个是读操作相关的锁,也称为共享锁。另一个是写操作相关的锁,也叫排他锁。多个读锁之间不互斥,写锁与写锁/写锁与读锁 互斥。
读写互斥demo代码:
package extthread;import service.Service;public class ThreadA extends Thread { private Service service; public ThreadA(Service service) { super(); this.service = service; } @Override public void run() { service.read(); }}package extthread;import service.Service;public class ThreadB extends Thread { private Service service; public ThreadB(Service service) { super(); this.service = service; } @Override public void run() { service.write(); }}package service;import java.util.concurrent.locks.ReentrantReadWriteLock;public class Service { private ReentrantReadWriteLock lock = new ReentrantReadWriteLock(); public void read() { try { try { lock.readLock().lock(); System.out.println("获得读锁A" + Thread.currentThread().getName() + " " + System.currentTimeMillis()); Thread.sleep(10000); } finally { lock.readLock().unlock(); } } catch (InterruptedException e) { e.printStackTrace(); } } public void write() { try { try { lock.writeLock().lock(); System.out.println("获得写锁B" + Thread.currentThread().getName() + " " + System.currentTimeMillis()); Thread.sleep(10000); } finally { lock.writeLock().unlock(); } } catch (InterruptedException e) { e.printStackTrace(); } }}}package test;import service.Service;import extthread.ThreadA;import extthread.ThreadB;public class Run { public static void main(String[] args) throws InterruptedException { Service service = new Service(); ThreadA a = new ThreadA(service); a.setName("A"); a.start(); Thread.sleep(1000); ThreadB b = new ThreadB(service); b.setName("B"); b.start(); }}输出结果:获得读锁AA 1511263792194获得写锁BB 1511263802194
读写”、“写读”和“写写”都是互斥的;而“读读”是异步的,非互斥的。
- 【java多线程编程核心技术】4.Lock的使用-笔记总结
- 《java多线程编程核心技术》核心笔记(三) Lock的使用
- 《java多线程编程核心技术》读书笔记4:Lock的使用
- 《Java多线程编程核心技术》(四)Lock的使用
- Java多线程编程核心技术--Lock的使用(一)
- Java多线程编程核心技术(第四章Lock的使用)
- java多线程编程核心技术4-Lock的使用
- Java多线程核心技术(四):Lock的使用
- 多线程编程核心技术读书笔记(四):Lock的使用
- 《java多线程编程核心技术》之Lock
- 【java多线程编程核心技术】1.java多线程技能-笔记总结
- java 多线程核心技术 第四章 lock的使用
- Java多线程编程核心技术笔记
- 《Java多线程编程核心技术》笔记
- 《Java多线程编程核心技术》-笔记
- 《Java 多线程编程核心技术》学习笔记及总结
- 【java多线程编程核心技术】3.线程间通信 -笔记总结
- 【java多线程编程核心技术】5.定时器Timer-笔记总结
- 对于天海投资未来发展,海航陈峰运筹帷幄
- Momenta详解ImageNet 2017夺冠架构SENet
- NameNode之租约管理
- Linux device tree(设备树)
- Java并发编程札记-(一)基础-07volatile详解
- 【java多线程编程核心技术】4.Lock的使用-笔记总结
- Android Recyclerview GridLayoutManager列间距
- Linux下配置软件安装源&更新
- 如何改变swagger请求的url
- Mybatis # 和 $ 的区别
- Akka(37): Http:客户端操作模式
- Source Insight如何改变背景颜色
- NameNode之文件系统目录树
- 24on物流链WMS仓库条码管理系统在企业对仓库的重要意义