第三章 JDK并发包

本文摘自《实战Java高并发程序设计》,了解详细内容推荐购买原版书籍。

第三章 JDK并发包

为了更好的支持并发程序,JDK内部提供了大量实用的API和框架。本章主要介绍这些JDK内部的功能,主要分为三大部分:
一、 首先介绍有关同步控制的工具,之前synchronized关键字就是一种同步控制手段。
二、 详细介绍JDK对线程池的支持,使用线程池,将能很大程度提高线程调度的性能。
三、 介绍JDK一些并发容器,这些容器专为并行访问设计,是高效、安全、稳定的工具。

3.1 多线程的团队协作:同步控制

同步控制是并发程序必不可少的重要手段。之前介绍的synchronized关键字就是一种最简单的。他决定一个线程是否可以访问临界区资源。
本节介绍synchronized、Object.wait()和Object.notify()方法的替代品(或者说增强版)——重入锁

3.1.1 synchronized的功能扩展:重入锁

重入锁可完全代替synchronized关键字。使用java.util.concurrent.locks.ReentrantLock类实现。下面为使用案例:
在这里插入图片描述
  开发人员必须手动指定何时加锁,何时释放锁。所以重入锁灵活性远远好于synchronized。注意:退出临界区时,记得释放锁。否则其他线程没机会访问了。
  为什么叫重入锁?因为这种锁是可以反复进入的。当然这里反复进入仅仅局限于一个线程。上述代码7-12行可以写成下面形式:
在这里插入图片描述
  这种情况下,一个线程连续获得两把锁是允许的!不过不允许这样做,同一个线程在第二次获得锁时,会和自己产生死锁。但是!获得多少次锁要记得释放多少次锁。
重入锁还可以提供中断处理的能力。

  • 中断响应

对于synchronized来说,如果一个线程在等待锁,会有两种情况:要么获得锁继续执行,要么继续等待。而使用重入锁,提供另外一种可能,就是线程可以中断。也就是说在等待锁的过程中,程序可以根据需要取消对锁的请求。
下面代码产生了一个死锁,但得益于中断,可以很好解决。:
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
  线程t1和t2启动后,t1线占用lock1,再占用lock2;t2先占用lock2,在请求lock1。因此,很容易形成t1和t2之间相互等待。这里对锁的请求,统一使用lockInterruptibly()方法。这是一个可以对中断进行响应的锁申请动作,即在等待锁的过程中,可以响应中断。
  代码47行,主线程main处于休眠,此时,两个线程处于死锁状态,49行,由于t2线程被中断,所以t2会放弃对lock1的申请,同时释放已获得lock2.导致t1可以将继续顺利得到lock2而继续执行下去。
  执行上述代码,输出:
在这里插入图片描述
可以看到,中断后,两个线程双双退出。但真正完成工作的只有t1。而t2放弃其任务直接退出,释放资源。

  • 锁申请等待时限

除等待外部通知之外,避免死锁还有另外一种方法,就是限时等待。通常无法判断为什么一个线程迟迟无法拿到锁,或许是因为死锁,获取因为产生了饥饿。如果给一个等待时间,让线程自动放弃,那么来说对系统是有意义的。可以使用tryLock()方法进行一次限时的等待。
  限时等待锁的使用:
在这里插入图片描述
  由于占用锁的线程会持有6秒,所以另外一个线程无法再5秒等待时间获得锁,请求失败。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值