Java基础教程:多线程基础——锁机制

显示锁

ReentrantLock

  ReentrantLock是一种标准的互斥锁,每次只允许一个线程持有ReentrantLock。

  使用ReentrantLock来保护对象状态:

  1. Lock lock = new ReentrantLock();
  2. lock.lock();
  3. try {
  4. //更新对象状态
  5. //捕获异常,并在必要时恢复不变性条件
  6. }finally {
  7. lock.unlock();
  8. }

  如果没有finally来释放Lock,相当于启动了一个定时炸弹。

ReentrantReadWriteLock

  互斥锁是一种保守的枷锁策略,它虽然避免了“写/写”冲突,“写/读”冲突,但是同样也避免了“读/读”操作。在许多情况下,数据结构上的操作都是“读操作”。若放宽加锁需求,允许多个执行读操作的线程同时访问数据结构,那么将提高程序的性能

  我们引入读写锁,它允许一个资源可以被多个读操作访问,或者被一个写操作访问,但两者不能同时进行。也就是说当写操作进行时,所有读操作都进入阻塞状态,只有写操作完成后,读操作才能获取到最新状态,避免了脏读的发生

  在如下的代码中,我们使用读写锁封装一个Map,来使其线程安全。

  1. public class ReadWriteMap<K,V> {
  2. private final Map<K,V> map;
  3. private final ReadWriteLock lock = new ReentrantReadWriteLock();
  4. private final Lock r = lock.readLock();
  5. private final Lock w = lock.writeLock();
  6.  
  7. public ReadWriteMap(Map<K,V> map){
  8. this.map = map;
  9. }
  10.  
  11. public V put(K key,V value){
  12. w.lock();
  13. try {
  14. return map.put(key,value);
  15. } finally {
  16. w.unlock();
  17. }
  18. }
  19.  
  20. public V get(Object key){
  21. r.lock();
  22. try {
  23. return map.get(key);
  24. } finally {
  25. r.unlock();
  26. }
  27. }
  28. }

  

使用Condition实现等待/通知

  关键字Synchronized与wait、notify/All方法相结合可以实现等待/通知模式,类ReentrantLock同样可以实现相同的功能,但是需要借助Condition

  Condition类是JDK5出现的新技术,可以实现 多路通知的功能,也就是在一个Lock对象里可以创建多个Condition(即对象监视器)实例,线程对象可以注册在指定的Condition中,从而可以有选择性地进行线程通知,在调度线程上更加灵活。

  必须在Condition.await()方法调用之前调用Lock.lock()方法获得同步监视器

MyService类

  1. public class MyService {
  2. private Lock lock = new ReentrantLock();
  3. public Condition condition = lock.newCondition();
  4.  
  5. public void await()
  6. {
  7. try {
  8. lock.lock();
  9. System.out.println("await的等待时间是"+System.currentTimeMillis());
  10. condition.await();
  11. } catch (InterruptedException e) {
  12. e.printStackTrace();
  13. }finally {
  14. lock.unlock();
  15. }
  16. }
  17.  
  18. public void signal()
  19. {
  20. try {
  21. lock.lock();
  22. System.out.println("signal的等待时间是"+System.currentTimeMillis());
  23. condition.signal();
  24. } catch (Exception e) {
  25. e.printStackTrace();
  26. }finally {
  27. lock.unlock();
  28. }
  29.  
  30. }
  31. }  

ThreadA类

  1. public class ThreadA extends Thread {
  2. private MyService myService;
  3.  
  4. public ThreadA(MyService myService) {
  5. this.myService = myService;
  6. }
  7.  
  8. @Override
  9. public void run() {
  10. myService.await();
  11. }
  12. }  

Main类

  1. public class Main {
  2. public static void main(String[] args) throws InterruptedException {
  3. MyService myService = new MyService();
  4. ThreadA threadA = new ThreadA(myService);
  5. threadA.start();
  6. Thread.sleep(3000);
  7. myService.signal();
  8. }
  9. }  

多个Condition实现通知部分线程

MyService类

  1. import java.util.concurrent.locks.Condition;
  2. import java.util.concurrent.locks.Lock;
  3. import java.util.concurrent.locks.ReentrantLock;
  4.  
  5. public class MySevice {
  6. private Lock lock = new ReentrantLock();
  7. public Condition conditionA = lock.newCondition();
  8. public Condition conditionB = lock.newCondition();
  9.  
  10. public void awaitA()
  11. {
  12. try {
  13. lock.lock();
  14. System.out.println("awaitA的start时间是"+System.currentTimeMillis());
  15. conditionA.await();
  16. System.out.println("awaitA的end时间是"+System.currentTimeMillis());
  17. } catch (InterruptedException e) {
  18. e.printStackTrace();
  19. }finally {
  20. lock.unlock();
  21. }
  22. }
  23.  
  24. public void awaitB()
  25. {
  26. try {
  27. lock.lock();
  28. System.out.println("awaitB的start时间是"+System.currentTimeMillis());
  29. conditionB.await();
  30. System.out.println("awaitB的end时间是"+System.currentTimeMillis());
  31. } catch (InterruptedException e) {
  32. e.printStackTrace();
  33. }finally {
  34. lock.unlock();
  35. }
  36. }
  37.  
  38. public void signalA()
  39. {
  40. try {
  41. lock.lock();
  42. System.out.println("signalA的等待时间是"+System.currentTimeMillis());
  43. conditionA.signalAll();
  44. } catch (Exception e) {
  45. e.printStackTrace();
  46. }finally {
  47. lock.unlock();
  48. }
  49.  
  50. }
  51. public void signalB()
  52. {
  53. try {
  54. lock.lock();
  55. System.out.println("signalB的等待时间是"+System.currentTimeMillis());
  56. conditionB.signalAll();
  57. } catch (Exception e) {
  58. e.printStackTrace();
  59. }finally {
  60. lock.unlock();
  61. }
  62.  
  63. }
  64. }  

ThreadA类

  1. public class ThreadA extends Thread {
  2. private MySevice myService;
  3.  
  4. public ThreadA(MySevice myService) {
  5. this.myService = myService;
  6. }
  7.  
  8. @Override
  9. public void run() {
  10. myService.awaitA();
  11. }
  12. }

ThreadB类

  1. public class ThreadB extends Thread {
  2. private MySevice myService;
  3.  
  4. public ThreadB(MySevice myService) {
  5. this.myService = myService;
  6. }
  7.  
  8. @Override
  9. public void run() {
  10. myService.awaitB();
  11. }
  12. }

Main类

  1. public class Main {
  2. public static void main(String[] args) throws InterruptedException {
  3. MySevice mySevice =new MySevice();
  4. ThreadA threadA = new ThreadA(mySevice);
  5. ThreadB threadB = new ThreadB(mySevice);
  6. threadA.start();
  7. threadB.start();
  8. Thread.sleep(3000);
  9. mySevice.signalA();
  10. }
  11. }

  

Java基础教程:多线程基础(4)——Lock的使用的更多相关文章

  1. java中的多线程 // 基础

    java 中的多线程 简介 进程 : 指正在运行的程序,并具有一定的独立能力,即 当硬盘中的程序进入到内存中运行时,就变成了一个进程 线程 : 是进程中的一个执行单元,负责当前程序的执行.线程就是CP ...

  2. Java基础教程——多线程:创建线程

    多线程 进程 每一个应用程序在运行时,都会产生至少一个进程(process). 进程是操作系统进行"资源分配和调度"的独立单位. Windows系统的"任务管理器&quo ...

  3. Java Hour 14 多线程基础

    有句名言,叫做10000小时成为某一个领域的专家.姑且不辩论这句话是否正确,让我们到达10000小时的时候再回头来看吧. 本文作者Java 现经验约为13 Hour,请各位不吝赐教. 多线程 这个是基 ...

  4. java开发之多线程基础篇

    首先我们先来了解下线程的生命周期上一张图: Java线程具有五中基本状态 新建状态(New):当线程对象对创建后,即进入了新建状态,如:Thread t = new MyThread(); 就绪状态( ...

  5. Java中的多线程基础

    1.线程与进程 进程: 进程是程序运行以及资源分配的基本单位,一个程序至少有一个进程. 如下图所示: 线程: 线程是CPU调度和分配的基本单位,一个进程至少有一个线程. 同一个进程中的线程共享进程资源 ...

  6. Java基础教程——网络基础知识

    参考阅读[中国互联网发展史]:https://zhuanlan.zhihu.com/p/61602252 协议 计算机网络中的通信必须有一些约定,这些约定称为"通信协议". 通信协 ...

  7. JAVA学习总结-多线程基础:

    参考书籍:疯狂JAVA讲义 1.进程和线程; 进程是处于运行过程中的程序;并且具有一定的独立功能;进程是系统进行系统资源分配和调度的一个独立单位. 一般而言,进程包括以下三个特征: 独立性:进程是系统 ...

  8. Java高并发-多线程基础

    一.什么是线程 线程是进程内的执行单元. 二.线程的基本操作 2.1 状态与操作 2.2 新建线程 Thread t1 = new Thread(new CreateThread()); t1.sta ...

  9. php基础教程-必备基础知识

    PHP 脚本在服务器上执行. 您应当具备的基础知识 在继续学习之前,您需要对下面的知识有基本的了解: HTML CSS JavaScript 如果您希望首先学习这些项目,请在我们的 首页 访问这些教程 ...

  10. Python笔记_第五篇_Python数据分析基础教程_NumPy基础

    1. NumPy的基础使用涵盖如下内容: 数据类型 数组类型 类型转换 创建数组 数组索引 数组切片 改变维度 2. NumPy数组对象: NumPy中的ndarray是一个多维数组对象,该兑现共有两 ...

随机推荐

  1. ios内存管理笔记(二)

    1)实现部分: 复制代码 @synthesize window=_window; @synthesize viewController=_viewController; 通常看到的都没有包含=部分,@ ...

  2. lua 的一些常用概念

    1 a={} //定义了一个table   a a[10000]=1 //这里的table中只有一个元素,10000,而不是有10000个元素 2 x=math.pi //定义了x等于π print( ...

  3. Hadoop之Linux源代码编译

    Hadoop开篇,按惯例.先编译源代码.导入到Eclipse.这样以后要了解那块,或者那块出问题了.直接找源代码. 编译hadoop2.4.1源代码之前.必须安装Maven和Ant环境,而且Hadoo ...

  4. hduoj1285确定比赛名次

     确定比赛名次 Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others) Total ...

  5. Git的提交忽略文件

    .gitingore文件内容如下 /target//.settings//.classpath/.project/logs/

  6. hibernate 过滤

    1.可以使用@Where的过滤,不过这种过滤式全局的,支持延迟加载. 2.可以使用@Filters,这种过滤不支持延迟加载. @Entity@Table(name = "qc315_tous ...

  7. 从有序数组中查找某个值 low_bound

    二分搜索 题意: 给定长度为n的单调不下降数列a0, ...an-1和一个数k,求满足ai>=k条件的最小的i. 不存在的情况下输出n. 输入: 5        3 2 3 3 5 6 输出: ...

  8. 撸代码--linux进程通信(基于共享内存)

    1.实现亲缘关系进程的通信,父写子读 思路分析:1)首先我们须要创建一个共享内存. 2)父子进程的创建要用到fork函数.fork函数创建后,两个进程分别独立的执行. 3)父进程完毕写的内容.同一时候 ...

  9. 自己定义字体之BMFont的使用

    ***************************************转载请注明出处:http://blog.csdn.net/lttree************************** ...

  10. solr入门之pinyin4j源代码改写动态加入扩展词及整合进war项目中

    1.初始化时载入用户定义的字典 package net.sourceforge.pinyin4j; import net.sourceforge.pinyin4j.multipinyin.Trie; ...