1.java.util.concurrent

线程同步:

  • 是因为多线程读写竞争资源需要同步
  • Java语言提供了synchronized/wait/notify来实现同步
  • 编写多线程同步很困难

所以Java提供了更高级的java.util.concurrent包:

  • 更高级的同步功能
  • 简化多线程程序的编写
  • JDK>= 1.5

2.ReetrantLock

java.util.locks.ReentrantLock用于替代synchronized加锁

synchronized是Java语言层面提供的,不需考虑异常

ReentrantLock是普通的Java类,要用try...finally来保证锁能够正确释放



当我们使用ReenTrantLock的时候,我们首先要通过new ReentrantLock()新建一个Lock对象。然后我们先试图用lock()方法获得当前对象的锁。如果我们获得锁成功,就进入try代码,最后在finally中用unlock()来释放这个锁。

注意:lock()方法必须在try代码之外完成。因为lock()可能会失败,而unlock()一定要在finally中完成。

  1. class Count{
  2. final Lock lock = new ReetrantLock(); //获得ReentrantLock对象
  3. public void inc(){
  4. lock.lock(); //获得当前对象的锁可能会失败,所以要放在try...finally外面
  5. try{
  6. n = n + 1;
  7. }finally{
  8. lock.unlock(); //释放锁
  9. }
  10. }

ReentrantLock:

  • 可重入锁,一个线程可多次获取同一个锁
  • lock()方法可获取锁
  • tryLock()方法可尝试获取锁并可指定超时。
  1. class Counter{
  2. final Lock lock = new ReentrantLock();
  3. private void inc() throws InterruptedException{
  4. if(lock.tryLock(1, TimeUnit.SECONDS)){
  5. try{
  6. n = n + 1;
  7. }finally {
  8. lock.unlock();
  9. }
  10. }
  11. }
  12. }

使用ReentrantLock比直接使用synchronized更安全,因为synchronized会导致线程要么获得锁,要的永远等待下去。而使用ReentrantLock的时候,我们通过tryLock()在失败的时候不会导致死锁。

3.示例

  1. import java.util.concurrent.locks.ReentrantLock;
  2. import java.util.concurrent.locks.Lock;
  3. class Counter{
  4. private Lock lock = new ReentrantLock();
  5. private int value = 0;
  6. public void add(int m){
  7. lock.lock();
  8. try{
  9. value += m;
  10. }finally {
  11. lock.unlock();
  12. }
  13. }
  14. public void dec(int m){
  15. lock.lock();
  16. try{
  17. value -= m;
  18. }finally {
  19. lock.unlock();
  20. }
  21. }
  22. public int get(){
  23. lock.lock();
  24. try{
  25. return this.value;
  26. }finally {
  27. lock.unlock();
  28. }
  29. }
  30. }
  31. public class Main{
  32. final static int LOOP = 100;
  33. public static void main(String[] args) throws Exception{
  34. Counter counter = new Counter();
  35. Thread t1 = new Thread(){
  36. public void run(){
  37. for(int i=0;i<LOOP;i++){
  38. counter.add(1);
  39. }
  40. }
  41. };
  42. Thread t2 = new Thread(){
  43. public void run(){
  44. for(int i=0;i<LOOP;i++){
  45. counter.dec(1);
  46. }
  47. }
  48. };
  49. t1.start();
  50. t2.start();
  51. t1.join();
  52. t2.join();
  53. System.out.println(counter.get());
  54. }
  55. }

4.总结:

  • ReentrantLock可以替代synchronized
  • ReentrantLock获取锁更安全
  • lock()获取锁在try...finally之前
  • 必须使用try... finally保证释放锁

廖雪峰Java11多线程编程-3高级concurrent包-1ReentrantLock的更多相关文章

  1. 廖雪峰Java11多线程编程-3高级concurrent包-5Atomic

    Atomic java.util.concurrent.atomic提供了一组原子类型操作: 如AtomicInteger提供了 int addAndGet(int delta) int increm ...

  2. 廖雪峰Java11多线程编程-3高级concurrent包-4Concurrent集合

    Concurrent 用ReentrantLock+Condition实现Blocking Queue. Blocking Queue:当一个线程调用getTask()时,该方法内部可能让给线程进入等 ...

  3. 廖雪峰Java11多线程编程-3高级concurrent包-6ExecutorService

    Java语言内置多线程支持: 创建线程需要操作系统资源(线程资源,栈空间) 频繁创建和销毁线程需要消耗大量时间 如果可以复用一个线程 线程池: 线程池维护若干个线程,处于等待状态 如果有新任务,就分配 ...

  4. 廖雪峰Java11多线程编程-3高级concurrent包-9Fork_Join

    线程池可以高效执行大量小任务: Fork/Join线程池可以执行一种特殊的任务: 把一个大任务拆成多个小任务并行执行 Fork/Join是在JDK 1.7引入的 示例:计算一个大数组的和 Fork/J ...

  5. 廖雪峰Java11多线程编程-3高级concurrent包-8CompletableFuture

    使用Future可以获得异步执行结果 Future<String> future = executor.submit(task); String result = future.get() ...

  6. 廖雪峰Java11多线程编程-3高级concurrent包-7Future

    JDK提供了ExecutorService接口表示线程池,可以通过submit提交一个任务. ExecutorService executor = Executors.newFixedThreadPo ...

  7. 廖雪峰Java11多线程编程-3高级concurrent包-3Condition

    Condition实现等待和唤醒线程 java.util.locks.ReentrantLock用于替代synchronized加锁 synchronized可以使用wait和notify实现在条件不 ...

  8. 廖雪峰Java11多线程编程-3高级concurrent包-2ReadWriteLock

    ReentrantLock保证单一线程执行 ReentrantLock保证了只有一个线程可以执行临界区代码: 临界区代码:任何时候只有1个线程可以执行的代码块. 临界区指的是一个访问共用资源(例如:共 ...

  9. 廖雪峰Java11多线程编程-2线程同步-3死锁

    1.线程锁可以嵌套 在多线程编程中,要执行synchronized块: 必须首先获得指定对象的锁 Java的线程锁是可重入的锁.对同一个对象,同一个线程,可以多次获取他的锁,即同一把锁可以嵌套.如以下 ...

随机推荐

  1. Git仓库操作命令

    创建仓库 git init 在当前目录执行,会生成.git目录文件,这个和SVN一致. 提交到仓库 git commit -m "first commit" -m:表示提交描述,必 ...

  2. springboot 简单搭建(thymeleaf 视图显示)

    接口访问参考:https://blog.csdn.net/hanjun0612/article/details/81625395 PS:调用接口和跳转网页 主要区别是 1 调用接口是 @RestCon ...

  3. 【笔记篇】斜率优化dp(五) USACO08MAR土地购(征)买(用)Land Acquisition

    好好的题目连个名字都不统一.. 看到这种最大最小的就先排个序嘛= =以x为第一关键字, y为第二关键字排序. 然后有一些\(x_i<=x_{i+1},且y_i<=y_{i+1}\)的土地就 ...

  4. Matplotlib---柱状图、直方图(高斯分布)

    # _*_ coding: gbk _*_ # @Author: Wonde # bar 直方图 import matplotlib.pyplot as plt # 绘图 from matplotli ...

  5. java继承,多态

    子类继承父类,用父类去接收子类,其实我觉得用父类,子类来形容继承关系是不恰当的,比如再发生多态的时候,Car c = new W();w是大众,你能说Car 和W是父子关系吗,我觉得用所属关系类描述可 ...

  6. Java 异常基本结构

    异常的定义:阻止当前方法或作用域继续执行的情况,即程序无法正常执行下去称之为异常. 异常的基本结构: 所有不正常的类都继承与Throwable类,包括Error类和Exception类 Error一般 ...

  7. [JZOJ6272] 2019.8.4【NOIP提高组A】整除

    题目 题目大意 求方程\((x^m-x)\mod n=0\)在整数范围\([1,n]\)的解的个数. \(n=\sum_{i=1}^{c}p_i\) 给出\(c\)和\(p_i\) 思考历程 作为数论 ...

  8. JQUERY(入口函数 选择器)

    入口函数   $(document).ready(function(){ });可以简写为$(function(){}) 选择器 基本选择器 元素选择器   $("p") 所有 & ...

  9. JVM中堆栈

    1.JVM是基于堆栈的虚拟机.JVM为每个新创建的线程都分配一个堆栈.也就是说,对于一个Java程序来说,它的运行就是通过对堆栈的操作来完成的.堆栈以帧为单位保存线程的状态.JVM对堆栈只进行两种操作 ...

  10. SQL Server SQLFetch()

    { /* 摘要 SQLFetch从结果集中提取下一个数据行集, 并返回所有绑定列的数据. 语法 C++ SQLRETURN SQLFetch( SQLHSTMT     StatementHandle ...