重入锁可以完全代替synchronized关键字.在JDK5.0的早期版本中,重入锁的性能远远好于synchronized,但是从JDK6.0开始.JDK在synchronized上做了大量的优化.使得两者的性能差距不大,
public class ReenterLock implements Runnable {
public static ReentrantLock lock = new ReentrantLock();
public static int i = 0; /**
* When an object implementing interface <code>Runnable</code> is used
* to create a thread, starting the thread causes the object's
* <code>run</code> method to be called in that separately executing
* thread.
* <p>
* The general contract of the method <code>run</code> is that it may
* take any action whatsoever.
*
* @see Thread#run()
*/
@Override
public void run() {
for (int j = 0; j < 10000000; j++) {
lock.lock();//加锁
try {
i++;
} finally {
lock.unlock();//释放锁
}
}
} public static void main(String[] args) throws InterruptedException {
ReenterLock t1 = new ReenterLock();//线程实例
Thread th1 = new Thread(t1);
Thread th2 = new Thread(t1);
th1.start();
th2.start();
th1.join();
th2.join();
System.out.println("i = " + i);
}
}
这里 我们使用重入锁保护临界区资源i 确保多线程对i操作的安全性,我们可以看出,与synchronized相比,重入锁有着显示的操作过程,开发人员必须手动指定何时加锁,何时释放锁,也正因为这样,重入锁对于逻辑控制的灵活性要远远好于synchronized,但是要必须释放锁,否则 其他线程就没有机会现在方法临界区资源了!另外重入锁允许一个线程连续几次获取同一把锁,但是释放锁的时候也要释放相同次数.
 
  • 中断响应  与synchronized相比,如果一个线程在等待锁,那么结果只要两种情况,1 获得这把锁执行, 2 他保持等待状态,而使用重入锁,则提供了另外一种可能性,那就是线程可以被中断,也就是在等待过程中,程序可以根据需要取消对锁的请求.
 
下面代码产生了一个死锁,但是得益于锁的中断,我们可以很轻松的解决死锁.
public class IntLock implements Runnable {
public static ReentrantLock lock1 = new ReentrantLock();
public static ReentrantLock lock2 = new ReentrantLock();
int lock; public IntLock(int lock) {
this.lock = lock;
} /**
* When an object implementing interface <code>Runnable</code> is used
* to create a thread, starting the thread causes the object's
* <code>run</code> method to be called in that separately executing
* thread.
* <p>
* The general contract of the method <code>run</code> is that it may
* take any action whatsoever.
*
* @see Thread#run()
*/
@Override
public void run() {
try {
if (lock == 1) {
lock1.lockInterruptibly();//锁1 这是一个可以对中断进行想要的锁申请动作!
try {
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
lock2.lockInterruptibly();//锁2 加锁
} else {
lock2.lockInterruptibly();
try {
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
lock1.lockInterruptibly();//锁1 加锁
}
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
if (lock1.isHeldByCurrentThread()) { //判断持有自己锁的线程是否是当前线程
lock1.unlock();
}
if (lock2.isHeldByCurrentThread()) {
lock2.unlock();
}
System.out.println(Thread.currentThread().getId() + ":线程退出");
}
} public static void main(String[] args) throws InterruptedException {
IntLock r1 = new IntLock(1);//线程实例 1
IntLock r2 = new IntLock(2);//线程实例 2
Thread t1 = new Thread(r1);//线程1
Thread t2 = new Thread(r2);//线程2
t1.start();
t2.start();
Thread.sleep(1000);//Main线程 休眠1s t2.interrupt();//中断其中一个线程 }
}
线程t1和t2启动后,t1占用rock1 在占用rock2  t2先占用rock2 然后请求rock1 因此很容易形成互相等待,  当我们让t2中断时,他放弃了申请lock1 然后释放了lock2 实际上是 t1线程 完成任务正常退出,而t2 是中断的,
  • 锁申请等待限时  除了等待通知之外,要避免死锁还有另外一种方法,那就是限时等待, 就是规定一个时间,超出时间没有拿到锁 就退出
public class TimeLock implements Runnable {
public static ReentrantLock lock = new ReentrantLock(); /**
* When an object implementing interface <code>Runnable</code> is used
* to create a thread, starting the thread causes the object's
* <code>run</code> method to be called in that separately executing
* thread.
* <p>
* The general contract of the method <code>run</code> is that it may
* take any action whatsoever.
*
* @see Thread#run()
*/
@Override
public void run() {
try {
if (lock.tryLock(5, TimeUnit.SECONDS)) {//试图获取锁,等待5秒 如果超时那就false
Thread.sleep(6000);
} else {
System.out.println("get lock failed");
}
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
if (lock.isHeldByCurrentThread()) {
lock.unlock();
}
}
} public static void main(String[] args) {
TimeLock r1 = new TimeLock();
Thread t1 = new Thread(r1);
Thread t2 = new Thread(r1);
t1.start();
t2.start();
}
}
在本例中,由于占用锁的线程会持有锁长达6s,故另一个线程无法在5s的等待时间内获得锁,因此,请求锁会失败!
 
      ReentrantLock.tryLock()方法可以不带参数直接运行,在这种情况下,当前线程会尝试获得锁,如果锁并未被其他线程占用,则申请会成功!并立即返回true,如果锁被其他线程占用,则档期你先吃不会进行任何等待,而是立即返回false.
 
public class TryLock implements Runnable {
public static ReentrantLock lock1 = new ReentrantLock();
public static ReentrantLock lock2 = new ReentrantLock();
int lock; public TryLock(int lock) {
this.lock = lock;
} /**
* When an object implementing interface <code>Runnable</code> is used
* to create a thread, starting the thread causes the object's
* <code>run</code> method to be called in that separately executing
* thread.
* <p>
* The general contract of the method <code>run</code> is that it may
* take any action whatsoever.
*
* @see Thread#run()
*/
@Override
public void run() {
if (lock == 1) {
while (true) {
if (lock1.tryLock()) {
try {
try {
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
if (lock2.tryLock()) {
try {
System.out.println(Thread.currentThread().getId() + ":My Job done");
return;
} finally {
lock2.unlock();
}
}
} finally {
lock1.unlock();
}
}
}
} else {
while (true) {
if (lock2.tryLock()) {
try {
try {
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
if (lock1.tryLock()) {
try {
System.out.println(Thread.currentThread().getId() + ":My Job done");
return;
} finally {
lock1.unlock();
}
}
} finally {
lock2.unlock();
}
}
}
}
} public static void main(String[] args) {
TryLock r1 = new TryLock(1);
TryLock r2 = new TryLock(2);
Thread t1 = new Thread(r1);
Thread t2 = new Thread(r2);
t1.start();
t2.start();
}
}
上述代码中.采用了非常容易死锁的加锁顺序,在一般情况下,这会导致t1和t2互相等待. 但是使用tryLock()后,就会得到大大改善,线程不会傻傻的等待,而是不停的尝试.因此只要时间足够的长,线程总是会得到所有需要的资源.
  • 公平锁 在大多情况下.锁的申请都是非公平的.两个线程同时申请锁a,谁先获得锁a呢 这是不一定的,系统只是会从这个锁的等待队列中随机挑选一个.而公平的锁,则不是这样的,他会按照时间的先后顺序,保证先到先得,后到后的,公平锁的一大特点就是,不会产生饥饿现象,只要你排队,最终还是可以得到资源的, 如果我们使用synchronized关键字进行锁控制,那么产生的锁就是非公平的,而重入锁循序我们对其公平性进行设置,下面是他的构造器
public ReentrantLock(boolean fair) {
    sync = fair ? new FairSync() : new NonfairSync();
}
 
 当参数fair为true时,表示锁是公平的,公平锁必须要求系统维护一个有序的队列,因此实现成本比较高,性能相对低下,因此默认锁是非公平的.

synchronized的功能拓展:重入锁(读书笔记)的更多相关文章

  1. 浅谈Java中的锁:Synchronized、重入锁、读写锁

    Java开发必须要掌握的知识点就包括如何使用锁在多线程的环境下控制对资源的访问限制 ◆ Synchronized ◆ 首先我们来看一段简单的代码: 12345678910111213141516171 ...

  2. synchronized 是可重入锁吗?为什么?

    什么是可重入锁? 关于什么是可重入锁,我们先来看一段维基百科的定义. 若一个程序或子程序可以“在任意时刻被中断然后操作系统调度执行另外一段代码,这段代码又调用了该子程序不会出错”,则称其为可重入(re ...

  3. java 可重入锁ReentrantLock的介绍

    一个小例子帮助理解(我们常用的synchronized也是可重入锁) 话说从前有一个村子,在这个村子中有一口水井,家家户户都需要到这口井里打水喝.由于井水有限,大家只能依次打水.为了实现家家有水喝,户 ...

  4. java高并发系列 - 第12天JUC:ReentrantLock重入锁

    java高并发系列 - 第12天JUC:ReentrantLock重入锁 本篇文章开始将juc中常用的一些类,估计会有十来篇. synchronized的局限性 synchronized是java内置 ...

  5. JUC 一 ReentrantLock 可重入锁

    java.util.concurrent.locks ReentrantLock即可重入锁,实现了Lock和Serializable接口 ReentrantLock和synchronized都是可重入 ...

  6. 可重入锁 & 自旋锁 & Java里的AtomicReference和CAS操作 & Linux mutex不可重入

    之前还是写过蛮多的关于锁的文章的: http://www.cnblogs.com/charlesblc/p/5994162.html <[转载]Java中的锁机制 synchronized &a ...

  7. Java并发编程-可重入锁

    可重入锁,也叫做递归锁,指的是同一线程 外层函数获得锁之后 ,内层递归函数仍可以获取该锁而不受影响.在JAVA环境下 ReentrantLock 和synchronized 都是 可重入锁. publ ...

  8. 可重入锁(good)

    可重入锁,也叫做递归锁,是指在一个线程中可以多次获取同一把锁,比如:一个线程在执行一个带锁的方法,该方法中又调用了另一个需要相同锁的方法,则该线程可以直接执行调用的方法[即可重入],而无需重新获得锁: ...

  9. Java可重入锁如何避免死锁

    本文由https://bbs.csdn.net/topics/390939500和https://zhidao.baidu.com/question/1946051090515119908.html启 ...

随机推荐

  1. 结构型设计模式之适配器模式(Adapter)

    结构 意图 将一个类的接口转换成客户希望的另外一个接口.A d a p t e r 模式使得原本由于接口不兼容而不能一起工作的那些类可以一起工作. 适用性 你想使用一个已经存在的类,而它的接口不符合你 ...

  2. JavaWeb响应下载(包含工具类)

    纸上得来终觉浅,绝知此事要躬行!今天博主分享是关于javaweb的响应(response)下载 以下是我的Demo: 页面我就粘主要部分的代码 <a href = "${pageCon ...

  3. [BZOJ1997][Hnoi2010]Planar 2-sat (联通分量) 平面图

    1997: [Hnoi2010]Planar Time Limit: 10 Sec  Memory Limit: 64 MBSubmit: 2317  Solved: 850[Submit][Stat ...

  4. 让Asp.net Web预启动

    IIS8以下解决方案: 当我们把网站部署在IIS7或IIS6S的时候,每当IIS或是Application Pool重启后,第一次请求网站反应总是很慢,原因大家都知道(不知道可以参考这个动画说明ASP ...

  5. HDU 6300.Triangle Partition-三角形-水题 (2018 Multi-University Training Contest 1 1003)

    6300.Triangle Partition 这个题就是输出组成三角形的点的下标. 因为任意三点不共线,所以任意三点就可以组成三角形,直接排个序然后输出就可以了. 讲道理,没看懂官方题解说的啥... ...

  6. CodeForces 445B DZY Loves Chemistry (并查集)

    题意: 有N种药剂编号 1 ~ N,然后有M种反应关系,这里有一个试管,开始时危险系数为 1,每当放入的药剂和瓶子里面的药剂发生反应时危险系数会乘以2,否则就不变,给出N个药剂和M种反应关系,求最大的 ...

  7. request与response对象.

    request与response对象. 1. request代表请求对象 response代表的响应对象. 学习它们我们可以操作http请求与响应. 2.request,response体系结构. 在 ...

  8. Python的并发并行[3] -> 进程[1] -> 多进程的基本使用

    多进程的基本使用 1 subprocess 常用函数示例 首先定义一个子进程调用的程序,用于打印一个输出语句,并获取命令行参数 import sys print('Called_Function.py ...

  9. @Transactional注解事务不起作用

    @Transactional注解事务不起作用 问题:今天在项目中碰到一个事务问题,使用@Transactional注解事务,抛出异常不会滚. 解决一:https://blog.csdn.net/u01 ...

  10. HttpWebRequest 请求 Api 及 异常处理

    HttpWebRequest request = WebRequest.CreateHttp(url); request.Method = "post"; request.Head ...