Lock锁的使用
在Java多线程中,可以使用synchronized关键字实现线程之间的同步互斥,在jdk1.5后新增的ReentrantLock类同样可达到此效果,且在使用上比synchronized更加灵活。
观察ReentrantLock类可以发现其实现了Lock接口
public class ReentrantLock implements Lock,java.io.Serializable
1、使用ReentrantLock实现同步
lock()方法:上锁
unlock()方法:释放锁
-
/*
-
* 使用ReentrantLock类实现同步
-
* */
-
class MyReenrantLock implements Runnable{
-
//向上转型
-
private Lock lock = new ReentrantLock();
-
public void run() {
-
//上锁
-
lock.lock();
-
for(int i = 0; i < 5; i++) {
-
System.out.println("当前线程名: "+ Thread.currentThread().getName()+" ,i = "+i);
-
}
-
//释放锁
-
lock.unlock();
-
}
-
}
-
public class MyLock {
-
public static void main(String[] args) {
-
MyReenrantLock myReenrantLock = new MyReenrantLock();
-
Thread thread1 = new Thread(myReenrantLock);
-
Thread thread2 = new Thread(myReenrantLock);
-
Thread thread3 = new Thread(myReenrantLock);
-
thread1.start();
-
thread2.start();
-
thread3.start();
-
}
-
}
由此我们可以看出,只有当当前线程打印完毕后,其他的线程才可继续打印,线程打印的数据是分组打印,因为当前线程持有锁,但线程之间的打印顺序是随机的。
即调用lock.lock()代码的线程就持有了“对象监视器”,其他线程只有等待锁被释放再次争抢。
2、使用Condition实现等待/通知
synchronized关键字结合wait()和notify()及notifyAll()方法的使用可以实现线程的等待与通知模式。在使用notify()、notifyAll()方法进行通知时,被通知的线程是JVM随机选择的。
类ReentrantLock类同样可以实现该功能,需要借助Condition对象,可实现“选择性通知”。Condition类是jdk1.5提供的,且在一个Lock对象中可以创建多个Condition(对象监视器)实例。
Condition类的await():是当前执行任务的线程处于等待状态
-
/*
-
* 错误的使用Condition实现等待、通知
-
* */
-
class MyCondition implements Runnable{
-
private Lock lock = new ReentrantLock();
-
public Condition condition = lock.newCondition();
-
public void run() {
-
try {
-
System.out.println("当前线程名:"+Thread.currentThread().getName()+" 开始等待时间:"+System.currentTimeMillis());
-
//线程等待
-
condition.await();
-
System.out.println("我陷入了等待...");
-
} catch (InterruptedException e) {
-
e.printStackTrace();
-
}
-
}
-
}
-
public class MyLock{
-
public static void main(String[] args) {
-
MyCondition myCondition = new MyCondition();
-
Thread thread1 = new Thread(myCondition,"线程1");
-
thread1.start();
-
}
-
}
观察运行结果可以发现,报出监视器出错的异常,解决的办法是我们必须在condition.await()方法调用前用lock.lock()代码获得同步监视器。对上述代码做出如下修改:
-
/*
-
* 使用Condition实现等待
-
* */
-
class MyCondition implements Runnable{
-
private Lock lock = new ReentrantLock();
-
public Condition condition = lock.newCondition();
-
public void run() {
-
try {
-
//上锁
-
lock.lock();
-
System.out.println("当前线程名:"+Thread.currentThread().getName()+" 开始等待时间:"+System.currentTimeMillis());
-
//线程等待
-
condition.await();
-
System.out.println("我陷入了等待...");
-
} catch (InterruptedException e) {
-
e.printStackTrace();
-
}finally {
-
//释放锁
-
lock.unlock();
-
System.out.println("锁释放了!");
-
}
-
}
-
}
-
public class MyLock{
-
public static void main(String[] args) {
-
MyCondition myCondition = new MyCondition();
-
Thread thread1 = new Thread(myCondition,"线程1");
-
thread1.start();
-
}
-
}
在控制台只打印出一句,原因是调用了Condition对象的await()方法,是的当前执行任务的线程进入等待状态。
Condition类的signal():是当前执行任务的线程处于等待状态
-
/*
-
* 使用Condition实现等待、通知
-
* */
-
class MyCondition implements Runnable{
-
private Lock lock = new ReentrantLock();
-
public Condition condition = lock.newCondition();
-
public void run() {
-
try {
-
//上锁
-
lock.lock();
-
System.out.println(" 开始等待时间:"+System.currentTimeMillis());
-
System.out.println("我陷入了等待...");
-
//线程等待
-
condition.await();
-
//释放锁
-
lock.unlock();
-
System.out.println("锁释放了!");
-
} catch (InterruptedException e) {
-
e.printStackTrace();
-
}
-
}
-
//通知方法
-
public void signal(){
-
try {
-
lock.lock();
-
System.out.println("结束等待时间:"+System.currentTimeMillis());
-
//通知等待线程
-
condition.signal();
-
} finally {
-
lock.unlock();
-
}
-
}
-
}
-
public class MyLock{
-
public static void main(String[] args) throws InterruptedException {
-
MyCondition myCondition = new MyCondition();
-
Thread thread1 = new Thread(myCondition,"线程1");
-
thread1.start();
-
Thread.sleep(3000);
-
myCondition.signal();
-
}
-
}
观察结果我们成功地实现了等待通知。
可以得知:Object类中的wait()方法等同于Condition类中的await()方法。
Object类中的wait(long timeout)方法等同于Condition类中的await(long time,TimeUnit unit)方法。
Object类中的notify()方法等同于Condition类中的singal()方法。
Object类中的notifyAll()方法等同于Condition类中的singalAll()方法。
3、生产者消费者模式
-
/*
-
* 生产者、消费者模式
-
* 一对一交替打印
-
* */
-
class MyServer{
-
private ReentrantLock lock = new ReentrantLock();
-
public Condition condition = lock.newCondition();
-
public Boolean flag = false;
-
public void set() {
-
try {
-
lock.lock();
-
while(flag == true) {
-
condition.await();
-
}
-
System.out.println("当前线程名:"+Thread.currentThread().getName()+" hello");
-
flag = true;
-
condition.signal();
-
} catch (InterruptedException e) {
-
e.printStackTrace();
-
}finally {
-
lock.unlock();
-
}
-
}
-
public void get() {
-
try {
-
lock.lock();
-
while(flag == false) {
-
condition.await();
-
}
-
System.out.println("当前线程名:"+Thread.currentThread().getName()+" lemon");
-
flag = false;
-
condition.signal();
-
} catch (InterruptedException e) {
-
e.printStackTrace();
-
}finally {
-
lock.unlock();
-
}
-
}
-
}
-
class MyCondition1 extends Thread{
-
private MyServer myServer;
-
public MyCondition1(MyServer myServer) {
-
super();
-
this.myServer = myServer;
-
}
-
public void run() {
-
for(int i = 0 ;i < Integer.MAX_VALUE;i++) {
-
myServer.set();
-
}
-
}
-
}
-
class MyCondition2 extends Thread{
-
private MyServer myServer;
-
public MyCondition2(MyServer myServer) {
-
super();
-
this.myServer = myServer;
-
}
-
public void run() {
-
for(int i = 0 ;i < Integer.MAX_VALUE;i++) {
-
myServer.get();
-
}
-
}
-
}
-
public class MyLock{
-
public static void main(String[] args) throws InterruptedException {
-
MyServer myServer = new MyServer();
-
MyCondition1 myCondition1 = new MyCondition1(myServer);
-
MyCondition2 myCondition2 = new MyCondition2(myServer);
-
myCondition1.start();
-
myCondition2.start();
-
}
-
}
-
/*
-
* 生产者、消费者模式
-
* 多对多交替打印
-
* */
-
class MyServer{
-
private ReentrantLock lock = new ReentrantLock();
-
public Condition condition = lock.newCondition();
-
public Boolean flag = false;
-
public void set() {
-
try {
-
lock.lock();
-
while(flag == true) {
-
System.out.println("可能会有连续的hello进行打印");
-
condition.await();
-
}
-
System.out.println("当前线程名:"+Thread.currentThread().getName()+" hello");
-
flag = true;
-
condition.signal();
-
} catch (InterruptedException e) {
-
e.printStackTrace();
-
}finally {
-
lock.unlock();
-
}
-
}
-
public void get() {
-
try {
-
lock.lock();
-
while(flag == false) {
-
System.out.println("可能会有连续的lemon进行打印");
-
condition.await();
-
}
-
System.out.println("当前线程名:"+Thread.currentThread().getName()+" lemon");
-
flag = false;
-
condition.signal();
-
} catch (InterruptedException e) {
-
e.printStackTrace();
-
}finally {
-
lock.unlock();
-
}
-
}
-
}
-
class MyCondition1 extends Thread{
-
private MyServer myServer;
-
public MyCondition1(MyServer myServer) {
-
super();
-
this.myServer = myServer;
-
}
-
public void run() {
-
for(int i = 0 ;i < Integer.MAX_VALUE;i++) {
-
myServer.set();
-
}
-
}
-
}
-
class MyCondition2 extends Thread{
-
private MyServer myServer;
-
public MyCondition2(MyServer myServer) {
-
super();
-
this.myServer = myServer;
-
}
-
public void run() {
-
for(int i = 0 ;i < Integer.MAX_VALUE;i++) {
-
myServer.get();
-
}
-
}
-
}
-
public class MyLock{
-
public static void main(String[] args) throws InterruptedException {
-
MyServer myServer = new MyServer();
-
MyCondition1[] myCondition1 = new MyCondition1[10];
-
MyCondition2[] myCondition2 = new MyCondition2[10];
-
for(int i = 0; i < 10; i++) {
-
myCondition1[i] = new MyCondition1(myServer);
-
myCondition2[i] = new MyCondition2(myServer);
-
myCondition1[i].start();
-
myCondition2[i].start();
-
}
-
}
-
}
4、公平锁与非公平锁
锁Lock分为“公平锁”和“非公平锁”。
公平锁:表示线程获取锁的顺序是按照线程加锁的顺序来的进行分配的,即先来先得FIFO先进先出顺序。
非公平锁:一种获取锁的抢占机制,是随机拿到锁的,和公平锁不一样的是先来的不一定先拿到锁,这个方式可能造成某些线程一直拿不到锁,结果就是不公平的·。
-
/*
-
* 公平锁
-
* */
-
class MyService{
-
private ReentrantLock lock;
-
public MyService(boolean isFair) {
-
super();
-
lock = new ReentrantLock(isFair);
-
}
-
public void serviceMethod() {
-
try {
-
lock.lock();
-
System.out.println("线程名:"+Thread.currentThread().getName()+"获得锁定");
-
} finally {
-
lock.unlock();
-
}
-
}
-
}
-
public class MyLock{
-
public static void main(String[] args) {
-
//设置当前为true公平锁
-
final MyService myService = new MyService(true);
-
Runnable runnable = new Runnable() {
-
public void run() {
-
System.out.println("线程名:"+Thread.currentThread().getName()+"运行了");
-
myService.serviceMethod();
-
}
-
};
-
Thread[] threads = new Thread[10];
-
for(int i = 0;i < 10; i++) {
-
threads[i] = new Thread(runnable);
-
}
-
for(int i = 0;i < 10; i++) {
-
threads[i].start();
-
}
-
}
-
}
由打印结果可以看出,基本呈现有序的状态,这就是公平锁的特点。
-
/*
-
* 非公平锁
-
* */
-
class MyService{
-
private ReentrantLock lock;
-
public MyService(boolean isFair) {
-
super();
-
lock = new ReentrantLock(isFair);
-
}
-
public void serviceMethod() {
-
try {
-
lock.lock();
-
System.out.println("线程名:"+Thread.currentThread().getName()+"获得锁定");
-
} finally {
-
lock.unlock();
-
}
-
}
-
}
-
public class MyLock{
-
public static void main(String[] args) {
-
//设置当前为true公平锁
-
final MyService myService = new MyService(false);
-
Runnable runnable = new Runnable() {
-
public void run() {
-
System.out.println("线程名:"+Thread.currentThread().getName()+"运行了");
-
myService.serviceMethod();
-
}
-
};
-
Thread[] threads = new Thread[10];
-
for(int i = 0;i < 10; i++) {
-
threads[i] = new Thread(runnable);
-
}
-
for(int i = 0;i < 10; i++) {
-
threads[i].start();
-
}
-
}
-
}
非公平锁的运行结果基本都是无须的,则可以表明先start()启动的线程并不一定先获得锁。
5、使用ReentrantReadWriteLock类
类ReentrantLock具有完全互斥排他的效果,即同一时间只有一个线程在执行ReentrantLock.lock()方法后的任务。这样虽然保证了实例变量的线程安全性,但是效率低下。所以在Java中提供有读写锁ReentrantReadWriteLock类,使其效率可以加快。在某些不需要操作实例变量的方法中,完全可以使用ReentrantReadWriteLock来提升该方法代码运行速度。
读写锁表示两个锁:
读操作相关的锁,也成为共享锁。
写操作相关的锁,也叫排他锁。
多个读锁之间不互斥,读锁与写锁互斥,多个写锁互斥。
在没有线程Thread进行写入操作时,进行读操作的多个Thread可以获取读锁,但是进行写入操作时的Thread只有获取写锁后才能进行写入操作。
(1)多个读锁共享
-
/*
-
* 多个读锁共享
-
* */
-
class MyService{
-
private ReentrantReadWriteLock lock = new ReentrantReadWriteLock();
-
public void read() {
-
try {
-
//读锁
-
lock.readLock().lock();
-
System.out.println("线程名: "+Thread.currentThread().getName()+"获取读锁" );
-
Thread.sleep(1000);
-
} catch (InterruptedException e) {
-
e.printStackTrace();
-
}finally {
-
//释放读锁
-
lock.readLock().unlock();
-
}
-
}
-
}
-
//线程1
-
class Thread1 extends Thread{
-
private MyService myService;
-
public Thread1(MyService myService) {
-
super();
-
this.myService = myService;
-
}
-
public void run() {
-
myService.read();
-
}
-
}
-
//线程2
-
class Thread2 extends Thread{
-
private MyService myService;
-
public Thread2(MyService myService) {
-
super();
-
this.myService = myService;
-
}
-
public void run() {
-
myService.read();
-
}
-
}
-
public class MyLock{
-
public static void main(String[] args) {
-
MyService myService = new MyService();
-
Thread1 thread1 = new Thread1(myService);
-
Thread2 thread2 = new Thread2(myService);
-
thread1.start();
-
thread2.start();
-
-
}
-
}
从打印结果可以看出,两个线程几乎同时进入lock()方法后面的代码。
说明在此时使用lock.readLock()读锁可以提高程序运行效率,允许多个线程同时执行lock()方法后的代码。
(2)多个写锁互斥
-
/*
-
* 多个写锁互斥
-
* */
-
class MyService{
-
private ReentrantReadWriteLock lock = new ReentrantReadWriteLock();
-
public void write() {
-
try {
-
//写锁
-
lock.writeLock().lock();
-
System.out.println("线程名: "+Thread.currentThread().getName()+"获取写锁,获得时间:"+System.currentTimeMillis() );
-
Thread.sleep(1000);
-
} catch (InterruptedException e) {
-
e.printStackTrace();
-
}finally {
-
//释放写锁
-
lock.writeLock().unlock();
-
}
-
}
-
}
-
//线程1
-
class Thread1 extends Thread{
-
private MyService myService;
-
public Thread1(MyService myService) {
-
super();
-
this.myService = myService;
-
}
-
public void run() {
-
myService.write();
-
}
-
}
-
//线程2
-
class Thread2 extends Thread{
-
private MyService myService;
-
public Thread2(MyService myService) {
-
super();
-
this.myService = myService;
-
}
-
public void run() {
-
myService.write();
-
}
-
}
-
public class MyLock{
-
public static void main(String[] args) {
-
MyService myService = new MyService();
-
Thread1 thread1 = new Thread1(myService);
-
Thread2 thread2 = new Thread2(myService);
-
thread1.start();
-
thread2.start();
-
-
}
-
}
使用写锁代码writeLock.lock()的效果就是同一时间只允许一个线程执行lock()方法后的代码。
(3)读写/写读互斥
-
/*
-
* 读写/写读互斥,
-
* */
-
class MyService{
-
private ReentrantReadWriteLock lock = new ReentrantReadWriteLock();
-
public void read() {
-
try {
-
//读锁
-
lock.readLock().lock();
-
System.out.println("线程名: "+Thread.currentThread().getName()+"获取读锁,获得时间:"+System.currentTimeMillis() );
-
Thread.sleep(1000);
-
} 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(1000);
-
} catch (InterruptedException e) {
-
e.printStackTrace();
-
}finally {
-
//释放写锁
-
lock.writeLock().unlock();
-
}
-
}
-
}
-
//线程1
-
class Thread1 extends Thread{
-
private MyService myService;
-
public Thread1(MyService myService) {
-
super();
-
this.myService = myService;
-
}
-
public void run() {
-
myService.read();
-
}
-
}
-
//线程2
-
class Thread2 extends Thread{
-
private MyService myService;
-
public Thread2(MyService myService) {
-
super();
-
this.myService = myService;
-
}
-
public void run() {
-
myService.write();
-
}
-
}
-
public class MyLock{
-
public static void main(String[] args) {
-
MyService myService = new MyService();
-
Thread1 thread1 = new Thread1(myService);
-
Thread2 thread2 = new Thread2(myService);
-
thread1.start();
-
thread2.start();
-
}
-
}
此运行结果说明“读写/写读”操作是互斥的。
由此可表明:只要出现“写”操作,就是互斥的。
Lock锁的使用的更多相关文章
- Lock锁的使用示例
Lock锁是java5用来代替synchronized的一种面向对象的锁的方案 public class LockDemo { /** * Lock是用来替换synchronized, 优点是Lock ...
- Android(java)学习笔记69:JDK5之后的Lock锁的概述和使用
1. Lock锁的概述: java.util.concurrent.locks,接口Lock 首先Lock是一个接口,Lock实现提供了比使用synchronized方法 和 同步代码块更为广泛的锁定 ...
- python多线程threading.Lock锁用法实例
本文实例讲述了python多线程threading.Lock锁的用法实例,分享给大家供大家参考.具体分析如下: python的锁可以独立提取出来 mutex = threading.Lock() #锁 ...
- Lock锁_线程_线程域
using System;using System.Collections.Generic;using System.ComponentModel;using System.Data;using Sy ...
- (删)Java线程同步实现二:Lock锁和Condition
在上篇文章(3.Java多线程总结系列:Java的线程同步实现)中,我们介绍了用synchronized关键字实现线程同步.但在Java中还有一种方式可以实现线程同步,那就是Lock锁. 一.同步锁 ...
- 转: 【Java并发编程】之二十:并发新特性—Lock锁和条件变量(含代码)
简单使用Lock锁 Java5中引入了新的锁机制--Java.util.concurrent.locks中的显式的互斥锁:Lock接口,它提供了比synchronized更加广泛的锁定操作.Lock接 ...
- 使用Lock锁生产者消费者模式
package com.java.concurrent; import java.util.concurrent.locks.Condition; import java.util.concurren ...
- JAVA基础再回首(二十五)——Lock锁的使用、死锁问题、多线程生产者和消费者、线程池、匿名内部类使用多线程、定时器、面试题
JAVA基础再回首(二十五)--Lock锁的使用.死锁问题.多线程生产者和消费者.线程池.匿名内部类使用多线程.定时器.面试题 版权声明:转载必须注明本文转自程序猿杜鹏程的博客:http://blog ...
- java并发编程的艺术——第五章总结(Lock锁与队列同步器)
Lock锁 锁是用来控制多个线程访问共享资源的方式. 一般来说一个锁可以防止多个线程同时访问共享资源(但有些锁可以允许多个线程访问共享资源,如读写锁). 在Lock接口出现前,java使用synchr ...
- Java中的Lock锁
Lock锁介绍: 在java中可以使用 synchronized 来实现多线程下对象的同步访问,为了获得更加灵活使用场景.高效的性能,java还提供了Lock接口及其实现类ReentrantLock和 ...
随机推荐
- Java经典面试题-不古出品
@ 目录 一.Java 基础 1.JDK 和 JRE 有什么区别? 2.== 和 equals 的区别是什么? 3.两个对象的 hashCode()相同,则 equals()也一定为 true,对吗? ...
- javascript 深拷贝与浅拷贝
javascript 深拷贝与浅拷贝 深拷贝与浅拷贝 赋值和深/浅拷贝的区别 浅拷贝的实现方式 1.Object.assign() 2.函数库lodash的_.clone方法 3.展开运算符... 4 ...
- Solon & Solon Cloud 1.5.62 发布,轻量级 Java 基础开发框架
Solon 已有120个生态扩展插件,此次更新主要为细节打磨,且对k8s和docker-compose更友好: 1.插件 solon.coud ,事件总线增加支持本地同主题多订阅模式(以支持同服务内, ...
- js--数组的 Array.of() 和 Array.from() 方法的使用总结
前言 JavaScript 中数组的本质是一个对象,它存在的 length 属性值随数组元素的长度变化,但是开发中经常会遇到拥有 length 属性和若干索引属性的对象,被称为类数组对象,类数组对象和 ...
- 关于JDBC中查询方法的抽取
萌新的JAVA学习笔记[1] 先来张伊蕾娜镇场~~ 简单描述 起初我们的查询方法时分为单个查询和全部查询,过于局限与繁琐,如此一来我们能不能想一个办法将所有类型的查询抽取出来并整合成为一个单独的工具方 ...
- 『与善仁』Appium基础 — 9、补充:C/S架构和B/S架构说明
目录 1.C/S架构和B/S架构概念 2.C/S结构与B/S架构的区别 3.C/S架构和B/S架构优点和缺点 (1)B/S模式的优点和缺点: (2)C/S模式的优点和缺点: 1.C/S架构和B/S架构 ...
- MySQL语法练习一
DESC t_dept ALTER TABLE t_dept ADD descri VARCHAR(20) ALTER TABLE t_dept ADD decribe VARCHAR(20) FIR ...
- 【JavaSE】finally块不被执行的情况总结
finally块不被执行的情况总结 2019-08-03 22:23:02 by冲冲 finally块的作用 通常用于处理善后工作.当try块里出现异常时,会立即跳出try块,到catch块匹配对 ...
- jenkins cron
1. Jenkins cron syntax Jenkins Cron 语法遵循Cron实用程序的语法(略有不同)具体来说,每行包含由TAB或SPACE分隔的5个字段(分时日月周): 分钟(Minut ...
- 华为云企业级Redis评测第一期:稳定性与扩容表现
摘要:采用Redis Labs推出的多线程压测工具memtier_benchmark对比测试下GaussDB(for Redis) 和原生Redis的特性差异. 本文分享自华为云社区<华为云企业 ...