关于互斥锁: html
所谓互斥锁, 指的是一次最多只能有一个线程持有的锁. 在jdk1.5以前, 咱们一般使用synchronized机制控制多个线程对共享资源的访问. 而如今, Lock提供了比synchronized机制更普遍的锁定操做, Lock和synchronized机制的主要区别: java
synchronized机制提供了对与每一个对象相关的隐式监视器锁的访问, 并强制全部锁获取和释放均要出如今一个块结构中, 当获取了多个锁时, 它们必须以相反的顺序释放. synchronized机制对锁的释放是隐式的, 只要线程运行的代码超出了synchronized语句块范围, 锁就会被释放. 编程
但有时也须要以更为灵活的方式使用锁,好比说在并发编程中有时候,有时候容许以任何顺序获取和释放多个锁,从而支持使用Lock。
api
而Lock机制必须显式的调用Lock对象的unlock()方法才能释放锁, 这为获取锁和释放锁不出如今同一个块结构中, 以及以更自由的顺序释放锁提供了可能. 多线程
一:synchronized的两种用法 并发
1.内部锁 spa
Java 提供了原子性的内置锁机制: sychronized 块。它包含两个部分:锁对象的引用和这个锁保护的代码块: .net
synchronized(lock) { // 访问或修改被锁保护的共享状态 }
2.重进入 线程
指的是同一个线程屡次试图获取它所占有的锁,请求会成功。当释放锁的时候,直到重入次数清零,锁才释放完毕 code
Public class Widget { Public synchronized void doSomething(){ … } } Public class LoggingWidget extends Widget { Public synchronized void doSomething(){ System.out.println(toString()+”:calling doSomething”); Super.doSomething(); } }
通常来讲,在多线程程序中,某个任务在持有某对象的锁后才能运行任务,其余任务只有在该任务释放同一对象锁后才能拥有对象锁,而后执行任务。因而,想到,同一个任务在持有同一个对象的锁后,在不释放锁的状况下,继续调用同一个对象的其余同步(synchronized)方法,该任务是否会再次持有该对象锁呢?
答案是确定的。
同一个任务在调用同一个对象上的其余synchronized方法,能够再次得到该对象锁。
synchronized m1(){ //加入此时对锁a的计数是N m2(); //进入m2的方法体以后锁计数是N+1,离开m2后是N } synchronized m2(){}
二:ReentrantLock 实现了Lock
一个可重入的互斥锁 Lock,它具备与使用 synchronized 方法和语句所访问的隐式监视器锁相同的一些基本行为和语义,但功能更强大。
public interface LockLock 实现提供了比使用 synchronized 方法和语句可得到的更普遍的锁定操做。此实现容许更灵活的结构,能够具备差异很大的属性,能够支持多个相关的 Condition 对象。
ReentrantLock 将由最近成功得到锁,而且尚未释放该锁的线程所拥有。当锁没有被另外一个线程所拥有时,调用 lock 的线程将成功获取该锁并返回。若是当前线程已经拥有该锁,此方法将当即返回。可使用 isHeldByCurrentThread() 和 getHoldCount() 方法来检查此状况是否发生。
此类的构造方法接受一个可选的公平 参数。当设置为 true 时,在多个线程的争用下,这些锁倾向于将访问权授予等待时间最长的线程。不然此锁将没法保证任何特定访问顺序。与采用默认设置(使用不公平锁)相比,使用公平锁的程序在许多线程访问时表现为很低的整体吞吐量(即速度很慢,经常极其慢),可是在得到锁和保证锁分配的均衡性时差别较小。不过要注意的是,公平锁不能保证线程调度的公平性。所以,使用公平锁的众多线程中的一员可能得到多倍的成功机会,这种状况发生在其余活动线程没有被处理而且目前并未持有锁时。还要注意的是,未定时的 tryLock 方法并无使用公平设置。由于即便其余线程正在等待,只要该锁是可用的,此方法就能够得到成功。
建议老是 当即实践,使用 lock 块来调用 try,在以前/以后的构造中,最典型的代码以下:class X { private final ReentrantLock lock = new ReentrantLock(); // ... public void m() { lock.lock(); // block until condition holds try { // ... method body } finally { lock.unlock() } } }
ReentrantLock 的lock机制有2种,忽略中断锁和响应中断锁,这给咱们带来了很大的灵活性。
好比:若是A、B 2个线程去竞争锁,A线程获得了锁,B线程等待,可是A线程这个时候实在有太多事情要处理,就是 一直不返回,B线程可能就会等不及了,想中断本身,再也不等待这个锁了,转而处理其余事情。这个时候ReentrantLock就提供了2种机制,
第一,B线程中断本身(或者别的线程中断它),可是ReentrantLock 不去响应,继续让B线程等待,你再怎么中断,我全当耳边风(synchronized原语就是如此);
第二,B线程中断本身(或者别的线程中断它),ReentrantLock 处理了这个中断,而且再也不等待这个锁的到来,彻底放弃。
代码:lock.lockInterruptibly();// 注意这里,能够响应中断