在java1.5中Lock对象来实现同步的效果,而且使用上更方便。

使用ReentrantLock实现同步

public class MyService {

    private Lock lock = new ReentrantLock();

    public void methodA(){
try {
lock.lock();
System.out.println("methodA begin threadName=" + Thread.currentThread().getName()+" time="+System.currentTimeMillis());
Thread.sleep(5000);
System.out.println("methodA end threadName=" + Thread.currentThread().getName()+" time="+System.currentTimeMillis());
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
lock.unlock();
}
} public void methodB(){
try {
lock.lock();
System.out.println("methodB begin threadName=" + Thread.currentThread().getName()+" time="+System.currentTimeMillis());
Thread.sleep(5000);
System.out.println("methodB end threadName=" + Thread.currentThread().getName()+" time="+System.currentTimeMillis());
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
lock.unlock();
}
}
} public class Test {
public static void main(String[] args) throws InterruptedException {
MyService service = new MyService();
new Thread(()->service.methodA()).start();
new Thread(()->service.methodA()).start();
new Thread(()->service.methodB()).start();
new Thread(()->service.methodB()).start(); }
}

测试结果:调用lock.lock()的线程就持有了“对象监视器”,其他线程只有等待锁被释放时再次争抢,效果和synchronized一样。

methodA begin threadName=Thread-0 time=1516242293668
methodA end threadName=Thread-0 time=1516242298669
methodA begin threadName=Thread-1 time=1516242298669
methodA end threadName=Thread-1 time=1516242303671
methodB begin threadName=Thread-2 time=1516242303671
methodB end threadName=Thread-2 time=1516242308672
methodB begin threadName=Thread-3 time=1516242308672
methodB end threadName=Thread-3 time=1516242313674

使用Condition实现等待/通知

public class MyService {
private Lock lock = new ReentrantLock();
private Condition condition = lock.newCondition();
public void await(){
try {
lock.lock();
System.out.println("await时间为"+System.currentTimeMillis());
condition.await();
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
lock.unlock();
}
} public void signal(){
try {
lock.lock();
System.out.println("signal时间为"+System.currentTimeMillis());
condition.signal();
} finally {
lock.unlock();
}
}
} public class Run { public static void main(String[] args) throws InterruptedException {
MyService service = new MyService();
new Thread(()->service.await()).start();
Thread.sleep(3000);
service.signal();
}
}

相似处:

1. 在使用Condition的await方法和signal方法之前比较先调用lock.lock(),否则会抛出异常,跟wait和nofity一样,需在synchronized的代码里运行一样

2. Object.wait() --> Condition.await(). Object.notify()--> Condition.signal(), Object.notifyAll() -->Condition.signalAll()

优点:

在一个Lock对象里面可以创建多个Condition实例,线程对象可以注册在指定的Condition中,从而可以有选择性的进行线程通知,在调度上更加灵活。

使用多个Condition实现通知部分线程

public class MyService {
private Lock lock = new ReentrantLock();
private Condition conditionA = lock.newCondition();
private Condition conditionB = lock.newCondition();
public void awaitA(){
try {
lock.lock();
System.out.println("begin awaitA时间为"+System.currentTimeMillis() + "Thread name="+Thread.currentThread().getName());
conditionA.await();
System.out.println("end awaitA时间为"+System.currentTimeMillis() + "Thread name="+Thread.currentThread().getName());
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
lock.unlock();
}
} public void awaitB(){
try {
lock.lock();
System.out.println("begin awaitB时间为"+System.currentTimeMillis() + "Thread name="+Thread.currentThread().getName());
conditionB.await();
System.out.println("end awaitB时间为"+System.currentTimeMillis() + "Thread name="+Thread.currentThread().getName());
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
lock.unlock();
}
} public void signalAll_A(){
try {
lock.lock();
System.out.println("signalAll_B 时间为"+System.currentTimeMillis() + "Thread name="+Thread.currentThread().getName());
conditionA.signalAll();
} finally {
lock.unlock();
}
} public void signalAll_B(){
try {
lock.lock();
System.out.println("signalAll_B 时间为"+System.currentTimeMillis() + "Thread name="+Thread.currentThread().getName());
conditionB.signalAll();
} finally {
lock.unlock();
}
}
} public class Run { public static void main(String[] args) throws InterruptedException {
MyService service = new MyService();
new Thread(()->service.awaitA()).start();
new Thread(()->service.awaitB()).start();
Thread.sleep(3000);
service.signalAll_A();
}
}

测试结果:线程B没有被唤醒

begin awaitA时间为1516244219035Thread name=Thread-0
begin awaitB时间为1516244219036Thread name=Thread-1
signalAll_B 时间为1516244222035Thread name=main
end awaitA时间为1516244222035Thread name=Thread-0

生产者和消费者

public class MyList {
private Lock lock = new ReentrantLock();
private Condition condition = lock.newCondition();
private volatile List<String> list = new ArrayList<>(10); public void get() {
try {
System.out.println("get,listSize="+list.size());
lock.lock();
while (list.size() == 0) {
System.out.println("get 等待,ThreadName=" + Thread.currentThread().getName());
condition.await();
}
System.out.println("get -1");
list.remove(0);
condition.signalAll();
} catch (InterruptedException e) {
e.printStackTrace();
} finally{
lock.unlock();
}
} public void set() {
try {
System.out.println("set,listSize="+list.size());
lock.lock();
while (list.size() == 10) {
System.out.println("set 等待,ThreadName=" + Thread.currentThread().getName());
condition.await();
}
System.out.println("set+1");
list.add("A");
condition.signalAll();
} catch (InterruptedException e) {
e.printStackTrace();
} finally{
lock.unlock();
}
}
} public class Run { public static void main(String[] args) throws InterruptedException {
MyList consumer = new MyList();
for(int i =0;i<10;i++){
new Thread(()->{
while(true){ consumer.set();}
}).start();
new Thread(()->{
while(true){ consumer.get();}
}).start();
}
}
}

ReentrantReadWriteLock

ReentrantLock具有完全互斥排他的效果,即在同一时间内只有一个线程在执行ReentrantLock.lock()方法后面的任务。但是效率相对低下,而是用ReentrantReadWriteLock读写锁,可以相对提高效率。读写锁也就是有两个锁,一个是和读相关的锁,也称共享锁,一个是和写相关的锁,也叫排它锁。只有读读锁之间不互斥,其他都互斥。

读读锁不互斥的例子

public class Service {

    private ReentrantReadWriteLock lock = new ReentrantReadWriteLock();
public void read(){
try {
lock.readLock().lock();
System.out.println("获得读锁"+Thread.currentThread().getName()+" " + System.currentTimeMillis());
Thread.sleep(10000);
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
lock.readLock().unlock();
}
}
} public class Run { public static void main(String[] args) throws InterruptedException {
Service service = new Service();
new Thread(()->service.read()).start();
new Thread(()->service.read()).start();
}
}

测试结果:几乎同时获得读锁,说明它们不互斥的

获得读锁Thread-0 1516246020468
获得读锁Thread-1 1516246020469

读写互斥的例子

public class Service {

    private ReentrantReadWriteLock lock = new ReentrantReadWriteLock();
public void read(){
try {
lock.readLock().lock();
System.out.println("获得读锁"+Thread.currentThread().getName()+" " + System.currentTimeMillis());
Thread.sleep(10000);
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
lock.readLock().unlock();
}
} public void write(){
try {
lock.writeLock().lock();
System.out.println("获得写锁"+Thread.currentThread().getName()+" " + System.currentTimeMillis());
Thread.sleep(10000);
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
lock.writeLock().unlock();
}
}
} public class Run { public static void main(String[] args) throws InterruptedException {
Service service = new Service();
new Thread(()->service.read()).start();
new Thread(()->service.write()).start();
}
}

测试结果:写操作需要等待读锁释放后才能获得

获得读锁Thread-0 1516246209130
获得写锁Thread-1 1516246219132

Java多线程技术-Lock/Condition的更多相关文章

  1. Java多线程技术学习笔记(二)

    目录: 线程间的通信示例 等待唤醒机制 等待唤醒机制的优化 线程间通信经典问题:多生产者多消费者问题 多生产多消费问题的解决 JDK1.5之后的新加锁方式 多生产多消费问题的新解决办法 sleep和w ...

  2. 赶紧收藏!王者级别的Java多线程技术笔记,我java小菜鸡愿奉你为地表最强!

    Java多线程技术概述 介绍多线程之前要介绍线程,介绍线程则离不开进程. 首先 , 进程 :是一个正在执行中的程序,每一个进程执行都有一个执行顺序,该顺序是一个执行路径,或者叫一个控制单元: 线程:就 ...

  3. Java多线程技术:实现多用户服务端Socket通信

    目录 前言回顾 一.多用户服务器 二.使用线程池实现服务端多线程 1.单线程版本 2.多线程版本 三.多用户与服务端通信演示 四.多用户服务器完整代码 最后 前言回顾 在上一篇<Java多线程实 ...

  4. Java多线程(五) Lock接口,ReentranctLock,ReentrantReadWriteLock

    在JDK5里面,提供了一个Lock接口.该接口通过底层框架的形式为设计更面向对象.可更加细粒度控制线程代码.更灵活控制线程通信提供了基础.实现Lock接口且使用得比较多的是可重入锁(Reentrant ...

  5. java多线程技术核心

    1.进程的三大特征: 独立性:拥有自己的独立的地址空间,一个进程不可以直接去访问其他进程的地址空间. 动态性:是一个系统中活动的指令的集合. 并发性:单个进程可以在多个处理器上并发进行,互不影响. 2 ...

  6. Java多线程基础——Lock类

    之前已经说道,JVM提供了synchronized关键字来实现对变量的同步访问以及用wait和notify来实现线程间通信.在jdk1.5以后,JAVA提供了Lock类来实现和synchronized ...

  7. java多线程技术之条件变量

    上一篇讲述了并发包下的Lock,Lock可以更好的解决线程同步问题,使之更面向对象,并且ReadWriteLock在处理同步时更强大,那么同样,线程间仅仅互斥是不够的,还需要通信,本篇的内容是基于上篇 ...

  8. Java多线程技术学习笔记(一)

    目录: 概述 多线程的好处与弊端 JVM中的多线程解析 多线程的创建方式之一:继承Thread类 线程的状态 多线程创建的方式之二:实现Runnable接口 使用方式二创建多线程的好处 多线程示例 线 ...

  9. Java多线程的~~~Lock接口和ReentrantLock使用

    在多线程开发.除了synchronized这个keyword外,我们还通过Lock接口来实现这样的效果.由Lock接口来实现 这样的多线程加锁效果的优点是非常的灵活,我们不在须要对整个函数加锁,并且能 ...

随机推荐

  1. day08-字符编码

    目录 计算机基础 启动应用程序 写文本的流程 Python解释器执行文件的原理 Python解释器与文本编辑器的区别 字符编码 字符编码发生在哪三个阶段 字符编码发展史与分类 总结 Python2与P ...

  2. CentOS下修改root用户名

    修改root登录用户名减少Linux云主机“被暴力破解”警告,登录云主机的时候就先显示登录失败多少次.其是公网有人在扫用弱密码破解登录. 所谓暴力破解,就是用“用户名“+”密码”穷举的方式进行远程登录 ...

  3. mybatis源码阅读-初始化过程(七)

    说明 mybatis初始化过程 就是解析xml到封装成Configuration对象 供后续使用 SqlSessionFactoryBuilder 代码例子 SqlSessionFactoryBuil ...

  4. CODEVS3147 矩阵乘法2

    ...怎么优化都是90分,最后一个点一直T掉,有谁过了请告诉我. Program CODEVS3147; ; ..maxn,-..maxn] of longint; n,q,i,j,k,k1,k2,k ...

  5. 洛谷 P1481 魔族密码

    P1481 魔族密码 题目描述 风之子刚走进他的考场,就…… 花花:当当当当~~偶是魅力女皇——花花!!^^(华丽出场,礼炮,鲜花) 风之子:我呕……(杀死人的眼神)快说题目!否则……-_-### 花 ...

  6. ZooKeeper的配置文件优化性能(转)

    一.前言 ZooKeeper的功能特性通过ZooKeeper配置文件来进行控制管理( zoo.cfg配置文件). ZooKeeper这样的设计其实是有它自身的原因的.通过前面对ZooKeeper的配置 ...

  7. mysql 源码 王恒 [mysql数据结构+mysql 执行计划]

    http://blog.chinaunix.net/uid/26896862/cid-156733-list-1.html http://www.it168.com/redian/wangheng/

  8. HDU 5501

    这题的01背包的特点很容易看出来,但其实发现,这个题讲究加入时候的顺序. 于是,用贪心排序,如代码中所示,如果A在B前面造成的分数损失更小,则排在前面...其实这个我也是猜的.. #include & ...

  9. tabBar颜色改动

    //未点击的颜色 [[UITabBarItem appearance] setTitleTextAttributes:[NSDictionary dictionaryWithObjectsAndKey ...

  10. password加密的算法

    加密原理:採用不同的加密算法对字符串进行加盐加密处理. 用以防止密文被md5字典进行反向暴力破解. 採用美国家安全局发布的加密算法(RFC 4357)加密,不採用自己创建的加密算法,以避免有安全漏洞. ...