线程并发五:线程安全之重入锁
来源:互联网 发布:红家 蓝家 知乎 编辑:程序博客网 时间:2024/06/05 10:18
重入锁简单介绍
之前介绍的synchronized关键字是一种最简单的控制方法。下面说一说线程安全的另一种实现方式——–重入锁
重入锁使用java.util.concurrent.loks.ReentrantLock 类来实现
a. lock() //获得锁,如果锁已被占用,则等待
b. lockInterruptibly() //获得锁,但优先响应中断
c. tryLock() //尝试获得锁,如果成功返回true.失败返回false.
d. tryLock(long time, TimeUnit nuit) //在指定时间内尝试获取锁
e. unlock() //释放锁
f. isHeldByCurrentThread() //检测当前线程是否持有锁。
import java.util.Date;import java.util.concurrent.locks.ReentrantLock;public class ReenterLockSimpleTest implements Runnable { public static ReentrantLock lock = new ReentrantLock(); public void sayHello(){ lock.lock(); lock.lock(); try { System.out.println("[" + new Date().getTime() + "]" + Thread.currentThread().getName() + ": say hello!!"); try { Thread.sleep(1000); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } } finally { lock.unlock(); lock.unlock(); } } public void run(){ while(true){ sayHello(); } } public static void main(String[] args){ Thread t1 = new Thread(new ReenterLockSimpleTest(),"test1"); Thread t2 = new Thread(new ReenterLockSimpleTest(),"test2"); t1.start(); t2.start(); }}
从打印可以看出,1秒只打印一条,两个线程相互交替。重入锁有着明显的操作痕迹,何时加锁,何时释放锁。也正是这样,重入锁对逻辑控制的灵活性要远远高于synchronized,重入锁之所以叫重入锁,那是因为这种锁可以反复进入的,当然这里的反复进入仅仅局限于同一个线程。并且,释放所得次数要是获取锁的次数一样。
2.中断响应
对于synchronized来说,如果一个线程在等待锁,只有两种情况,要么得到锁,要么继续等待,而重入锁提供另一种可能,那就是线程中断。
import java.util.concurrent.locks.ReentrantLock;public class InterruptedReenterLock implements Runnable { public static ReentrantLock lock1 = new ReentrantLock(); public static ReentrantLock lock2 = new ReentrantLock(); @Override public void run() { // TODO Auto-generated method stub try { if(!Thread.currentThread().isInterrupted()){ if("test1".equals(Thread.currentThread().getName())){ lock1.lockInterruptibly(); try { Thread.sleep(500); } catch (InterruptedException e) { // TODO: handle exception } lock2.lockInterruptibly(); }else { lock2.lockInterruptibly(); try { Thread.sleep(500); } catch (InterruptedException e) { // TODO: handle exception } lock1.lockInterruptibly(); } } } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } finally { if(lock1.isHeldByCurrentThread()){ lock1.unlock(); } if(lock2.isHeldByCurrentThread()){ lock2.unlock(); } System.out.println(Thread.currentThread().getName() + " 线程退出!"); } } public static void main(String[] args) throws InterruptedException{ Thread t1 = new Thread(new InterruptedReenterLock(),"test1"); Thread t2 = new Thread(new InterruptedReenterLock(),"test2"); t1.start(); t2.start(); Thread.sleep(2000); t2.interrupt(); }}
如上代码会出现两个线程相互等待的情况,当线程2发生中断后,释放所有的锁,线程1在线程2释放锁之后获得锁,两个线程先后结束。
3.限时申请锁
tryLock() 方法限时等待,有两种方式, 一种为限时申请锁,需要设定时间, 一种为尝试获取锁,无论成功还是失败直接返回,不等待。
import java.util.Date;import java.util.concurrent.TimeUnit;import java.util.concurrent.locks.ReentrantLock;public class TryLockTiem implements Runnable { public static ReentrantLock lock = new ReentrantLock(); public void sayHello(){ try { if(lock.tryLock(4, TimeUnit.SECONDS)){ System.out.println("[" + new Date().getTime() + "]" + Thread.currentThread().getName() + ": get lock!!"); Thread.sleep(6000); }else{ System.out.println("[" + new Date().getTime() + "]" + Thread.currentThread().getName() + ": get nothing!!"); } } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } finally { if(lock.isHeldByCurrentThread()){ lock.unlock(); } } } public void run(){ while(true){ sayHello(); } } public static void main(String[] args){ Thread t1 = new Thread(new TryLockTiem(),"test1"); Thread t2 = new Thread(new TryLockTiem(),"test2"); t1.start(); t2.start(); }}
import java.util.Date;import java.util.concurrent.locks.ReentrantLock;public class TryLockTiem implements Runnable { public static ReentrantLock lock = new ReentrantLock(); public void sayHello(){ try { if(lock.tryLock()){ System.out.println("[" + new Date().getTime() + "]" + Thread.currentThread().getName() + ": get lock!!"); Thread.sleep(2000); }else{ System.out.println("[" + new Date().getTime() + "]" + Thread.currentThread().getName() + ": get nothing!!"); Thread.sleep(1000); } } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } finally { if(lock.isHeldByCurrentThread()){ System.out.println("[" + new Date().getTime() + "]" + Thread.currentThread().getName() + ": release lock!!"); lock.unlock(); } } } public void run(){ while(true){ sayHello(); } } public static void main(String[] args){ Thread t1 = new Thread(new TryLockTiem(),"test1"); Thread t2 = new Thread(new TryLockTiem(),"test2"); t1.start(); t2.start(); }}
- 线程并发五:线程安全之重入锁
- Java 并发之线程安全
- 线程并发四:线程安全之synchronized
- 线程安全与并发探究(五)
- java并发编程基础之线程安全
- 并发编程之线程安全HashMap_ConcurrentHashMap
- java并发:线程安全
- 并发4-线程安全
- java-并发-线程安全
- java-并发-线程安全
- 线程并发工具--线程安全集合
- 并发编程の线程安全
- 【多线程高并发】线程安全
- Java 并发 线程安全 ThreadLocal
- Java并发编程详解之 线程安全和对象共享
- Java并发编程实践笔记之-什么是线程安全
- Java 并发编程之线程安全(随手笔记)
- java线程安全之并发Queue(十三)
- Hibernate 映射配置,主键自增长,复合主键
- springboot集成PageHelper
- Android Dialog全屏后遮挡物理返回键问题解决
- springboot整合mybatis
- 学习kail linux的几个不错的网站
- 线程并发五:线程安全之重入锁
- C#语言之“string格式的日期时间字符串转为DateTime类型”的方法
- Replication error Agent message code 20002 due to OS error 2.
- Linux-HA 高可用开源方案 Keepalived VS Heartbeat 的选择
- 15基于opencv的旋转_仿射变换_SURF特征点检测
- Android报错集锦之一:You need to use a Theme.AppCompat theme (or descendant) with this activity.
- c++11通过变参模板实现特殊的数据结构和算法
- spring和mybactis的整合
- Glide使用中遇到的问题