在编码的过程中。有时候我们不得不借助锁同步来保证线程安全。synchronizedkeyword在上一篇博客中已经介绍。自从JDK5開始,加入了还有一种锁机制:ReentrantLock。

二者的差别

1、lock是jdk5之后代码层面实现的,synchronized是JVM层面实现的。

2、synchronized在出现异常的时候可以自己主动释放锁。而lock必须在finally块中unlock()主动释放锁。否则会死锁。

3、在竞争不激烈的时候synchronized的性能是比lock好一点的。可是当竞争非常激烈时synchronized的性能会相对几十倍的下降,由于lock用了新的锁机制,新的Lock机制终于归结到一个原子性操作上。

4、synchronized无法中断一个正在等候获得锁的线程。也无法通过投票得到锁,假设不想等下去,也就没法得到锁;而lock能够。

5、ReentrantLock能够採用FIFO的策略进行竞争,更加公平。

基本使用方法

先写个简单的样例看一下:

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.ReentrantLock;
public class TestReentrantLock {
public static void main(String[] args) {
final ReentrantLock rLock = new ReentrantLock();
final Condition condition = rLock.newCondition();
ExecutorService executorService = Executors.newFixedThreadPool(5);
Runnable opt = new Runnable() {
@Override
public void run() {
rLock.lock();
System.out.println(Thread.currentThread().getName()+"--->>lock()");
try {
condition.await();
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
System.out.println(Thread.currentThread().getName()+"--->>unlock()");
rLock.unlock();
}
}
}; for (int i = 0; i < 4; i++) {
executorService.submit(opt);
} Runnable release = new Runnable() {
@Override
public void run() {
rLock.lock();
try {
Thread.sleep(2000);
System.out.println(Thread.currentThread().getName()+"--->>signalAll()");
condition.signalAll();
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
rLock.unlock();
}
}
};
executorService.submit(release);
executorService.shutdown();
}
}

执行结果:

pool-1-thread-1--->>lock()

pool-1-thread-2--->>lock()

pool-1-thread-3--->>lock()

pool-1-thread-4--->>lock()

pool-1-thread-5--->>signalAll()

pool-1-thread-1--->>unlock()

pool-1-thread-2--->>unlock()

pool-1-thread-3--->>unlock()

pool-1-thread-4--->>unlock()

上面代码中有个Condition,它的三个方法await 、 signal 和 signalAll,与基类的wait、notify和notifyAll方法相相应,由于它们不能覆盖Object上的相应方法。所以就起了这三个奇葩的名字。由上面的代码能够看出ReentrantLock和synchronized使用方法是基本同样的。

中断ReentrantLock

实比例如以下:

package co.etc.concurrent;
import java.util.concurrent.locks.ReentrantLock;
public class ReentrantLockSample {
public static void main(String[] args) {
testReentrantLock();
}
public static void testReentrantLock() {
final SampleSupportLock support = new SampleSupportLock();
Thread first = new Thread(new Runnable() {
public void run() {
try {
support.doSomething();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
});
Thread second = new Thread(new Runnable() {
public void run() {
try {
support.doSomething();
} catch (InterruptedException e) {
System.out.println("InterruptedException--->>");
}
}
});
executeTest(first, second);
}
public static void executeTest(Thread a, Thread b) {
a.start();
try {
Thread.sleep(100);
b.start();
Thread.sleep(1000);
System.out.println("---->>>interrupt()");
b.interrupt();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
abstract class SampleSupport {
protected int counter;
public void startTheCountdown() {
long currentTime = System.currentTimeMillis();
for (;;) {
long diff = System.currentTimeMillis() - currentTime;
if (diff > 2000) {
break;
}
}
}
}
class SampleSupportLock extends SampleSupport {
private final ReentrantLock lock = new ReentrantLock();
public void doSomething() throws InterruptedException {
lock.lockInterruptibly();
System.out.println(Thread.currentThread().getName()
+ "doSomething()--->>");
startTheCountdown();
try {
counter++;
} finally {
lock.unlock();
}
System.out.println("counter---->>>"+counter);
}
}

执行结果:

Thread-0doSomething()--->>

---->>>interrupt()

InterruptedException--->>

counter---->>>1

执行结果表明第二个线程被中断了,这是由于我用的是lock.lockInterruptibly();在主线程中我调用了b.interrupt();二synchronized是没法做到的

公平性

实例代码例如以下:

import java.util.Collection;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
public class TestFairLock {
private static Lock fairLock = new ReentrantLock2(true);
private static Lock unfairLock = new ReentrantLock2();
public static void main(String[] args) {
TestFairLock testFairLock = new TestFairLock();
// testFairLock.unfair();
testFairLock.fair();
}
public void fair() {
System.out.println("fair version");
for (int i = 0; i < 5; i++) {
Thread thread = new Thread(new Job(fairLock)) {
public String toString() {
return getName();
}
};
thread.setName("" + i);
thread.start();
}
// sleep 5000ms
}
public void unfair() {
System.out.println("unfair version");
for (int i = 0; i < 5; i++) {
Thread thread = new Thread(new Job(unfairLock)) {
public String toString() {
return getName();
}
};
thread.setName("" + i);
thread.start();
}
// sleep 5000ms
}
private static class Job implements Runnable {
private Lock lock;
public Job(Lock lock) {
this.lock = lock;
}
@Override
public void run() {
for (int i = 0; i < 5; i++) {
lock.lock();
try {
System.out.println("Thread--->>"
+ Thread.currentThread().getName());
} finally {
lock.unlock();
}
}
}
}
private static class ReentrantLock2 extends ReentrantLock {
private static final long serialVersionUID = 1773716895097002072L;
public ReentrantLock2(boolean b) {
super(b);
}
public ReentrantLock2() {
super();
}
public Collection<Thread> getQueuedThreads() {
return super.getQueuedThreads();
}
}
}

执行结果

unfair version

Thread--->>0

Thread--->>0

Thread--->>0

Thread--->>0

Thread--->>0

Thread--->>1

Thread--->>1

Thread--->>1

Thread--->>1

Thread--->>1

Thread--->>2

Thread--->>2

Thread--->>2

Thread--->>2

Thread--->>2

Thread--->>3

Thread--->>3

Thread--->>3

Thread--->>3

Thread--->>3

Thread--->>4

Thread--->>4

Thread--->>4

Thread--->>4

Thread--->>4

fair version

Thread--->>0

Thread--->>0

Thread--->>1

Thread--->>3

Thread--->>0

Thread--->>4

Thread--->>2

Thread--->>1

Thread--->>3

Thread--->>0

Thread--->>4

Thread--->>2

Thread--->>1

Thread--->>3

Thread--->>0

Thread--->>4

Thread--->>2

Thread--->>1

Thread--->>3

Thread--->>4

Thread--->>2

Thread--->>1

Thread--->>3

Thread--->>4

Thread--->>2

从执行结果看到用ReentrantLock(boolean fair)构建的锁,相对ReentrantLock()是更公平的,当fair为true时採用的是FIFO策略,所

以各个线程可以更平均的分配时间。

java concurrent之ReentrantLock的更多相关文章

  1. java中的 java.util.concurrent.locks.ReentrantLock类中的lockInterruptibly()方法介绍

    在java的 java.util.concurrent.locks包中,ReentrantLock类实现了lock接口,lock接口用于加锁和解锁限制,加锁后必须释放锁,其他的线程才能进入到里面执行, ...

  2. java中的 java.util.concurrent.locks.ReentrantLock类的使用方式

    实现了lock的类为:ReentrantLock 接口的方式解释: lock()方法为获取锁对象,如果未获取到锁就一直获取锁. trylock():为布尔值,返回是否获取到了锁,如果没有获取到锁则返回 ...

  3. java Concurrent包学习笔记(三):ReentrantLock

    一.可重入性的理解 从名字上理解,ReenTrantLock的字面意思就是再进入的锁,其实synchronized关键字所使用的锁也是可重入的,两者关于这个的区别不大.两者都是同一个线程每进入一次,锁 ...

  4. Java并发控制:ReentrantLock Condition使用详解

    生产者-消费者(producer-consumer)问题,也称作有界缓冲区(bounded-buffer)问题,两个进程共享一个公共的固定大小的缓冲区.其中一个是生产者,用于将消息放入缓冲区:另外一个 ...

  5. java concurrent包的学习(转)

    java concurrent包的学习(转) http://my.oschina.net/adwangxiao/blog/110188 我们都知道,在JDK1.5之前,Java中要进行业务并发时,通常 ...

  6. [Java Concurrent] 并发访问共享资源的简单案例

    EvenGenerator 是一个偶数生成器,每调用一个 next() 就会加 2 并返回叠加后结果.在本案例中,充当被共享的资源. EvenChecker 实现了 Runnable 接口,可以启动新 ...

  7. Java并发之ReentrantLock

    一.ReentrantLock简介 ReentrantLock字面意义上理解为可重入锁.那么怎么理解可重入这个概念呢?或者说和我们经常用的synchronized又什么区别呢? ReentrantLo ...

  8. java并发之ReentrantLock学习理解

    简介 java多线程中可以使用synchronized关键字来实现线程间同步互斥,但在jdk1.5中新增加了ReentrantLock类也能实现同样的效果,并且在扩展功能上也更加强大,比如具有嗅探锁定 ...

  9. Java并发编程-ReentrantLock源码分析

    一.前言 在分析了 AbstractQueuedSynchronier 源码后,接着分析ReentrantLock源码,其实在 AbstractQueuedSynchronizer 的分析中,已经提到 ...

随机推荐

  1. 如何实现JS函数的重载

    javascript不能支持函数的重载,如下: function f(length) { alert("高为:"+length); } function f(length,widt ...

  2. WordPress 后台上传自定义网站Logo

    需求: 众所周知一般网站的logo都是固定的所以我在做网站时也是使用的静态logo文件,但最近用wp给一个客户做的网站时,因为网站现在的logo可能会需要重新设计,所以客户提出了需要在后台可以自己修改 ...

  3. DFA 算法实现关键词匹配

    起因: 从网页中爬去的页面.须要推断是否跟预设的关键词匹配(是否包括预设的关键词),并返回全部匹配到的关键词 . 眼下pypi 上两个实现 ahocorasick https://pypi.pytho ...

  4. CommonCode升级:把不常用的Sqlite独立出去

    CommonCode大概一年多没有更新了,今天碰到一件闹心的事情,结果用一行代码解决了京东购物车信息提取工具.一不小心,把一贯以来的一个念头又给惹起来了:就是把程序做成又给独立的exe,不要这么多dl ...

  5. freemarker 模板开发入门

    数据模型 scalars标量:从根 root 開始指定它的路径,每级之间用点来分隔. 如:whatnot.fruits sequences 序列:使用数组的方括号方式来訪问一个序列的子变量. 如:an ...

  6. MVC4.0网站发布

    一.VS2010下MVC4.0项目的发布 首先,生成网站发布文件. 第一步,"右击"要发布的MVC4.0项目,选择"发布(B)..."选项,如图: 第二步,在& ...

  7. PHP高级教程-包含

    PHP 包含文件 PHP include 和 require 语句 在 PHP 中,您可以在服务器执行 PHP 文件之前在该文件中插入一个文件的内容. include 和 require 语句用于在执 ...

  8. h5 微场景

    兔展: http://www.rabbitpre.com/ 易企秀: http://www.eqxiu.com/site/show 云来: http://www.liveapp.cn/

  9. fis3 scss 版本报错

    fis3 scss编译需要安装的node版本为4.x,node版本高了fis会报错.如下图所示:

  10. 使用Python创建MySQL数据库实现字段动态添加以及动态的插入数据

    应用场景: 我们须要设计一个数据库来保存多个文档中每一个文档的keyword. 假如我们每一个文档字符都超过了1000,取当中出现频率最大的为我们的keyword. 如果每个文档的keyword都超过 ...