多线程总结-同步之ReentrantLock
1 ReentrantLock与synchronized对比
ReentrantLock与synchronized都是为了同步加锁,但ReentrantLock相对效率比synchronized高,量级较轻。
synchronized在JDK1.5版本开始,尝试优化。到JDK1.7版本后,优化效率已经非常好了。在绝对效率上,不比reentrantLock差多少。使用ReentrantLock,必须手工释放锁标记。一般都是在finally代码块中定义释放锁标记的unlock方法。
2.示例用法
2.1 基本用法
lock()与unlock()就像synchronized同步代码块的开始与结束,使用ReentrantLocky一定要记得unlock()解锁
package com.bernardlowe.concurrent.t03;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
public class Test_01 {
Lock lock = new ReentrantLock();
void m1(){
try{
lock.lock(); // 加锁
for(int i = 0; i < 10; i++){
TimeUnit.SECONDS.sleep(1);
System.out.println("m1() method " + i);
}
}catch(InterruptedException e){
e.printStackTrace();
}finally{
lock.unlock(); // 解锁
}
}
void m2(){
lock.lock();
System.out.println("m2() method");
lock.unlock();
}
public static void main(String[] args) {
final Test_01 t = new Test_01();
new Thread(new Runnable() {
@Override
public void run() {
t.m1();
}
}).start();
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
new Thread(new Runnable() {
@Override
public void run() {
t.m2();
}
}).start();
}
}
2.2 尝试锁
尝试锁,顾名思义是尝试获取锁标记trylock(),有两种方式
无参尝试锁:会根据是否能获取当前锁标记返回对应值
boolean tryLock();
有参阻塞尝试锁, 阻塞尝试锁,阻塞参数代表等待超时时间。
boolean tryLock(long time, TimeUnit unit) throws InterruptedException;
/**
* 尝试锁
*/
package com.bernardlowe.concurrent.t03;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
public class Test_02 {
Lock lock = new ReentrantLock();
void m1(){
try{
lock.lock();
for(int i = 0; i < 10; i++){
TimeUnit.SECONDS.sleep(1);
System.out.println("m1() method " + i);
}
}catch(InterruptedException e){
e.printStackTrace();
}finally{
lock.unlock();
}
}
void m2(){
boolean isLocked = false;
try{
// 尝试锁, 如果有锁,无法获取锁标记,返回false。
// 如果获取锁标记,返回true
// isLocked = lock.tryLock();
// 阻塞尝试锁,阻塞参数代表的时长,尝试获取锁标记。
// 如果超时,不等待。直接返回。
isLocked = lock.tryLock(5, TimeUnit.SECONDS);
if(isLocked){
System.out.println("m2() method synchronized");
}else{
System.out.println("m2() method unsynchronized");
}
}catch(Exception e){
e.printStackTrace();
}finally{
if(isLocked){
// 尝试锁在解除锁标记的时候,一定要判断是否获取到锁标记。
// 如果当前线程没有获取到锁标记,会抛出异常。
lock.unlock();
}
}
}
public static void main(String[] args) {
final Test_02 t = new Test_02();
new Thread(new Runnable() {
@Override
public void run() {
t.m1();
}
}).start();
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
new Thread(new Runnable() {
@Override
public void run() {
t.m2();
}
}).start();
}
}
2.3 可打断
先解释下线程的几种状态:
阻塞状态: 包括普通阻塞,等待队列,锁池队列。
普通阻塞: sleep(10000), 可以被打断。调用thread.interrupt()方法,可以打断阻塞状态,抛出异常。
等待队列: wait()方法被调用,也是一种阻塞状态,只能由notify唤醒。无法打断
锁池队列: 无法获取锁标记。不是所有的锁池队列都可被打断
- 使用ReentrantLock的lock方法,获取锁标记的时候,如果需要阻塞等待锁标记,无法被打断。
- 使用ReentrantLock的lockInterruptibly方法,获取锁标记的时候,如果需要阻塞等待,可以被打断。
示例代码
主线程启动了两个线程t1,t2,t1调用m1(),t2调用m2()
当主线程调用interrupt()方法,可以打断t2线程的阻塞等待锁,抛出异常
package com.bernardlowe.concurrent.t03;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
public class Test_03 {
Lock lock = new ReentrantLock();
void m1(){
try{
lock.lock();
for(int i = 0; i < 5; i++){
TimeUnit.SECONDS.sleep(1);
System.out.println("m1() method " + i);
}
}catch(InterruptedException e){
e.printStackTrace();
}finally{
lock.unlock();
}
}
void m2(){
try{
lock.lockInterruptibly(); // 可尝试打断,阻塞等待锁。可以被其他的线程打断阻塞状态
System.out.println("m2() method");
}catch(InterruptedException e){
System.out.println("m2() method interrupted");
}finally{
try{
lock.unlock();
}catch(Exception e){
e.printStackTrace();
}
}
}
public static void main(String[] args) {
final Test_03 t = new Test_03();
new Thread(new Runnable() {
@Override
public void run() {
t.m1();
}
}).start();
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
Thread t2 = new Thread(new Runnable() {
@Override
public void run() {
t.m2();
}
});
t2.start();
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
t2.interrupt();// 打断线程休眠。非正常结束阻塞状态的线程,都会抛出异常。
}
}
结果如图
2.4 公平锁
操作系统cpu,为了保证效率,线程的执行机制是竞争机制,或者说是随机机制,是不公平的,使用ReentrantLock实现公平锁,是非常简单的,只需要在创建ReentrantLock的时候传一个参数ReentrantLock lock = new ReentrantLock(true);
示例代码:
TestReentrantlock是公平锁
TestSync是非公平锁
/**
* 公平锁
*/
package com.bernardlowe.concurrent.t03;
import java.util.concurrent.locks.ReentrantLock;
public class Test_04 {
public static void main(String[] args) {
TestReentrantlock t = new TestReentrantlock();
//TestSync t = new TestSync();
Thread t1 = new Thread(t);
Thread t2 = new Thread(t);
t1.start();
t2.start();
}
}
class TestReentrantlock extends Thread{
// 定义一个公平锁
private static ReentrantLock lock = new ReentrantLock(true);
public void run(){
for(int i = 0; i < 5; i++){
lock.lock();
try{
System.out.println(Thread.currentThread().getName() + " get lock");
}finally{
lock.unlock();
}
}
}
}
class TestSync extends Thread{
public void run(){
for(int i = 0; i < 5; i++){
synchronized (this) {
System.out.println(Thread.currentThread().getName() + " get lock in TestSync");
}
}
}
}
公平锁结果:
非公平锁结果:
多线程总结-同步之ReentrantLock的更多相关文章
- JAVA - 多线程的同步
多线程的同步 1. 锁对象. 应用场景:当某个数据可能被其他线程修改时,给涉及到数据的方法上锁,保证同一时刻只有拥有这个锁的线程能访问该数据,其他要调用这个方法的线程被阻塞.注意:必须是不同线程访问同 ...
- java多线程系列(五)---synchronized ReentrantLock volatile Atomic 原理分析
java多线程系列(五)---synchronized ReentrantLock volatile Atomic 原理分析 前言:如有不正确的地方,还望指正. 目录 认识cpu.核心与线程 java ...
- Java多线程的同步控制记录
Java多线程的同步控制记录 一.重入锁 重入锁完全可以代替 synchronized 关键字.在JDK 1.5 早期版本,重入锁的性能优于 synchronized.JDK 1.6 开始,对于 sy ...
- Java多线程之同步集合和并发集合
Java多线程之同步集合和并发集合 不管是同步集合还是并发集合他们都支持线程安全,他们之间主要的区别体现在性能和可扩展性,还有他们如何实现的线程安全. 同步集合类 Hashtable Vector 同 ...
- Java基础知识笔记(五:多线程的同步问题)
编写多线程程序往往是为了提高资源的利用率,或者提高程序的运行效率,或者更好地监控程序的运行过程等.多线程同步处理的目的是为了让多个线程协调地并发工作.对多线程进行同步处理可以通过同步方法和同步语句块实 ...
- 转载自~浮云比翼:Step by Step:Linux C多线程编程入门(基本API及多线程的同步与互斥)
Step by Step:Linux C多线程编程入门(基本API及多线程的同步与互斥) 介绍:什么是线程,线程的优点是什么 线程在Unix系统下,通常被称为轻量级的进程,线程虽然不是进程,但却可 ...
- Step by Step:Linux C多线程编程入门(基本API及多线程的同步与互斥)
介绍:什么是线程,线程的优点是什么 线程在Unix系统下,通常被称为轻量级的进程,线程虽然不是进程,但却可以看作是Unix进程的表亲,同一进程中的多条线程将共享该进程中的全部系统资源,如虚拟地址空间, ...
- Python标准库08 多线程与同步 (threading包)
Python主要通过标准库中的threading包来实现多线程.在当今网络时代,每个服务器都会接收到大量的请求.服务器可以利用多线程的方式来处理这些请求,以提高对网络端口的读写效率.Python是一种 ...
- 【转】【玩转cocos2d-x之二十三】多线程和同步03-图片异步加载
原创作品,转载请标明:http://blog.csdn.net/jackystudio/article/details/15334159 cocos2d-x中和Android,Windows都 一样, ...
随机推荐
- Qt SizePolicy 属性(每个控件都有一个合理的缺省sizePolicy。QWidget.size()默认返回值是(640, 480),QWidget.sizeHint()默认返回值是(-1, -1))
控件的sizePolicy说明控件在布局管理中的缩放方式.Qt提供的控件都有一个合理的缺省sizePolicy,但是这个缺省值有时不能适合 所有的布局,开发人员经常需要改变窗体上的某些控件的sizeP ...
- Android零基础入门第63节:过时但仍值得学习的选项卡TabHost
原文:Android零基础入门第63节:过时但仍值得学习的选项卡TabHost 由于前几天参加一个学习培训活动,几乎每天都要从早晨7点到晚上一两点,没有什么时间来分享,实在抱歉中间断更了几天.从今天开 ...
- 有什么很好的软件是用 Qt 编写的?(尘中远)
作者:尘中远链接:http://www.zhihu.com/question/19630324/answer/19365369来源:知乎 http://www.cnblogs.com/grandyan ...
- Using 3D engines with Qt(可以整合到Qt里,不影响)
A number of popular 3D engines can be integrated with Qt: Contents [hide] 1 Ogre 2 Irrlicht 3 OpenS ...
- qt的demo中,经常可以看到emum
最近开始看QT的文档,发现了很多好东西,至少对于我来说 收获很多~~~ 当然很多东西自己还不能理解的很透彻,也是和朋友讨论以后才渐渐清晰的,可能对于QT中一些经典的用意我还是存在会有些认识上的偏差,欢 ...
- coci2018 题解
plahte 给定一些矩形和一些有颜色的点,求每个矩形上有多少种颜色的点,保证矩形只有包含和不相交两种关系,规模 \(10^5\). 把每个矩形看成一个点,用扫描线建出森林,同时也顺便处理点. 然后做 ...
- xe5 firemonkey关闭应用程序
在FMX中,由Activity替代了Form的概念,虽然TForm类仍然存在,但MainForm通过关闭函数无法结束程序,使用Application.Terminate均无效,调整为: uses ...
- libevent for qt的讨论
一直对Qt官方的QtNetwork模块抱有遗憾,Qt自带的网络模块用的是select模型,无法支持高并发的服务器开发.最近在网上看到有个libevent for qt的东西,它直接替换了Qt的sele ...
- elasticsearch local debug环境搭建
最近计划看看elasticsearch的源码,首先得把local debug环境搞定. 下载源码.因为公司产线是5.6.5,所以就下载了5.6.5的代码. 源码编译.先进入到/elasticsearc ...
- OSGI资料
http://osgi.codeplex.com/ http://www.iopenworks.com/