在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. CDR软件-CorelDRAW软件下载,618活动

    618我有诚意,你呢? 不花钱的618,是残缺的618 给自己一个放肆shopping的机遇 活动力度不够大? 继续升级,终极体验 618疯狂倒计时! 同志们,如果你错过了之前的抢先购和升级活动 那么 ...

  2. MFC TAB控件顺序

    在MFC中添加控件后,按Ctrl+d可以改变控件TAB顺序,怕自己忘了,一个神奇的东西,记下. 关于改变Tab顺序的方法有以下几种: 方法一:在动态创建控件的时候STYLE设置成为WS_CHILD|W ...

  3. 解决 i5 6500 安装黑苹果 Sierra 显卡不正常问题

    i5 6500内置HD 530显卡,装好Sierra显卡驱动不太正常. 先下载Clover configurator 用Clover configurator加载 EFI (Mount EFI)分区 ...

  4. js  计算是今天多少周

    /** * 判断年份是否为润年 * * @param {Number} year */ function isLeapYear(year) { return (year % 400 == 0) || ...

  5. c/c++排坑(2) -- c语言中的符号重载

    所谓的符号重载就是在不同的上下文环境里有不同的意义.甚至有些关键字也被重载而具有好几种意义,这也是C语言的作用域规则对程序员不那么清晰的主要原因. 本章内容摘自<c专家编程>P37. 大家 ...

  6. [ZJOJ] 5772【NOIP2008模拟】今天你AK了吗

    Description AK:All kill“你为什么没背书?”“没有为什么,我就是没背书.”“……我去年买了个表,G—U—N!”头铁王InFleaKing把背书的时间都拿去列排列了......n= ...

  7. HDU - 2159 FATE(二维dp之01背包问题)

    题目: ​ 思路: 二维dp,完全背包,状态转移方程dp[i][z] = max(dp[i][z], dp[i-1][z-a[j]]+b[j]),dp[i][z]表示在杀i个怪,消耗z个容忍度的情况下 ...

  8. Django-搭建win7虚拟环境-virtualenv

    为什么要配置Django虚拟环境? 例如:在开发Python Django的时候,系统安装的Python3只有一个版本:3.6.所有第三方的包都会被pip安装到Python3的site-package ...

  9. LeetCode 712. Minimum ASCII Delete Sum for Two Strings

    Given two strings s1, s2, find the lowest ASCII sum of deleted characters to make two strings equal. ...

  10. webpack-dev-server和webpack

    指导小伙伴在webstorm+nodejs环境下新建项目时,小伙伴出现了一个很神奇的问题:没有执行webpack-dev-server情况下,即使执行npm init,也不会出现package.jso ...