20.ReenterLock重入锁
import java.util.concurrent.locks.ReentrantLock;
/**
* 重入锁 ReenterLock 一个线程允许连续获得同一把锁,注意:必须释放相同次数,释放次数多,会异常,少了相当于线程还持有这个锁,其他线程无法进入临界区
* 需要手动指定何时加锁何时释放锁
*
ReenterLock几个重要方法:
- lock():获得锁,如果锁已经被占用,则等待
- lockInterruptibly():获得锁,但优先响应中断
- tryLock():尝试获得锁,成功返回true,失败返回false,该方法不等待,立即返回
- tryLock(long time,TimeUnit unit):在给定时间内尝试获得锁
- unlock():释放锁
*/
public class ReentrantLockDemo implements Runnable{
public static Integer i = 0;
public static ReentrantLock lock = new ReentrantLock();
@Override
public void run() {
for (int j = 0; j < 10000000; j++) {
lock.lock();
try {
i++;
}finally {
lock.unlock();
}
}
}
public static void main(String[] args) throws InterruptedException{
ReentrantLockDemo r = new ReentrantLockDemo();
Thread thread1 = new Thread(r);
Thread thread2 = new Thread(r);
thread1.start();thread2.start();
thread1.join();thread2.join();
System.out.println(i);//20000000
}
}
中断处理
import java.util.concurrent.locks.ReentrantLock;
/**
* 避免死锁
* 重入锁的中断处理能力
*/
public class IntLock implements Runnable{
public static ReentrantLock lock1 = new ReentrantLock();
public static ReentrantLock lock2 = new ReentrantLock();
int lock;
public IntLock(int lock) {
this.lock = lock;
}
@Override
public void run() {
try {
if (lock==1){
lock1.lockInterruptibly();
Thread.sleep(500);
lock2.lockInterruptibly();//可以对中断进行响应的锁
}else {
lock2.lockInterruptibly();
Thread.sleep(500);
lock1.lockInterruptibly(); //22行
}
}catch (InterruptedException e){
e.printStackTrace();
}finally {
//检查当前线程是否拥有该锁
if (lock1.isHeldByCurrentThread()) lock1.unlock();
if (lock2.isHeldByCurrentThread()) lock2.unlock();
System.out.println(Thread.currentThread().getId()+":线程退出");
}
}
public static void main(String[] args) throws InterruptedException{
IntLock i1 = new IntLock(1);
IntLock i2 = new IntLock(2);
Thread t1 = new Thread(i1);
Thread t2 = new Thread(i2);
t1.start();
t2.start();
Thread.sleep(1000);
t2.interrupt(); //中断t2 ,t2放弃对lock1的申请,同时释放已获得的lock2
//java.lang.InterruptedException
// at java.util.concurrent.locks.AbstractQueuedSynchronizer.doAcquireInterruptibly(AbstractQueuedSynchronizer.java:898)
// at java.util.concurrent.locks.AbstractQueuedSynchronizer.acquireInterruptibly(AbstractQueuedSynchronizer.java:1222)
// at java.util.concurrent.locks.ReentrantLock.lockInterruptibly(ReentrantLock.java:335)
// at com.combat.IntLock.run(IntLock.java:22)
// at java.lang.Thread.run(Thread.java:748)
//10:线程退出
//9:线程退出
}
}
限时等待
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.ReentrantLock;
/**
* 限时等待锁
*/
public class TimeLockDemo implements Runnable{
public static ReentrantLock lock = new ReentrantLock();
@Override
public void run() {
try {
if (lock.tryLock(5, TimeUnit.SECONDS)){ //等待时间,计时单位
Thread.sleep(6000);
}else {
System.out.println("get lock failed");
}
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
if (lock.isHeldByCurrentThread())lock.unlock();
}
}
public static void main(String[] args){
TimeLockDemo demo = new TimeLockDemo();
Thread t1 = new Thread(demo);
Thread t2 = new Thread(demo);
t1.start();
t2.start();
}
//get lock failed
//由于占用锁的线程为6秒,另一个线程无法在5秒的等待时间内获得锁,因此请求锁失败
}
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.ReentrantLock;
/**
* tryLock
* 限时等待锁 无参数 如果锁被其他线程占用,则当前线程不会进行等待,而是立即返回false,不会引起线程等待
*/
public class TimeLockDemo2 implements Runnable{
public static ReentrantLock lock1 = new ReentrantLock();
public static ReentrantLock lock2 = new ReentrantLock();
int lock;
public TimeLockDemo2(int lock) {
this.lock = lock;
}
@Override
public void run() {
if (lock == 1){
while (true){
if (lock1.tryLock()){
try {
try {
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
if (lock2.tryLock()){
try {
System.out.println(Thread.currentThread().getId()+":my job done");
return;
} finally {
lock2.unlock();
}
}
} finally {
lock1.unlock();
}
}
}
}else {
while (true){
if (lock2.tryLock()){
try {
try {
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
if (lock1.tryLock()){
try {
System.out.println(Thread.currentThread().getId()+":my job done");
return;
} finally {
lock1.unlock();
}
}
} finally {
lock2.unlock();
}
}
}
}
}
public static void main(String[] args){
TimeLockDemo2 r1 = new TimeLockDemo2(1);
TimeLockDemo2 r2 = new TimeLockDemo2(1);
Thread t1 = new Thread(r1);
Thread t2 = new Thread(r2);
t1.start();
t2.start();
}
//9:my job done
//10:my job done
}
公平锁
import java.util.concurrent.locks.ReentrantLock;
/**
* 公平锁
* synchronized产生的锁是非公平锁
* 重入锁可以设置公平性
*/
public class FairLock implements Runnable{
public static ReentrantLock lock = new ReentrantLock(true);
@Override
public void run() {
while (true){
try {
lock.lock();
System.out.println(Thread.currentThread().getName()+"获得锁");
} finally {
lock.unlock();
}
}
}
public static void main(String[] args) throws InterruptedException{
FairLock lock = new FairLock();
Thread t1 = new Thread(lock, "thread_t1");
Thread t2 = new Thread(lock, "thread_t2");
t1.start();
t2.start();
}
//...
//thread_t2获得锁
//thread_t1获得锁
//thread_t2获得锁
//thread_t1获得锁
//thread_t2获得锁
//...
//两个线程基本交替获得锁
//而非公平锁,一个线程会倾向于再次获得已持有的锁,这种分配方式是高效的,但无公平性可言
}
20.ReenterLock重入锁的更多相关文章
- AQS学习(二) AQS互斥模式与ReenterLock可重入锁原理解析
1. MyAQS介绍 在这个系列博客中,我们会参考着jdk的AbstractQueuedLongSynchronizer,从零开始自己动手实现一个AQS(MyAQS).通过模仿,自己造轮子来学习 ...
- 可重入锁(good)
可重入锁,也叫做递归锁,是指在一个线程中可以多次获取同一把锁,比如:一个线程在执行一个带锁的方法,该方法中又调用了另一个需要相同锁的方法,则该线程可以直接执行调用的方法[即可重入],而无需重新获得锁: ...
- Java多线程——深入重入锁ReentrantLock
简述 ReentrantLock 是一个可重入的互斥(/独占)锁,又称为“独占锁”. ReentrantLock通过自定义队列同步器(AQS-AbstractQueuedSychronized,是实现 ...
- 浅谈Java中的锁:Synchronized、重入锁、读写锁
Java开发必须要掌握的知识点就包括如何使用锁在多线程的环境下控制对资源的访问限制 ◆ Synchronized ◆ 首先我们来看一段简单的代码: 12345678910111213141516171 ...
- synchronized 是可重入锁吗?为什么?
什么是可重入锁? 关于什么是可重入锁,我们先来看一段维基百科的定义. 若一个程序或子程序可以“在任意时刻被中断然后操作系统调度执行另外一段代码,这段代码又调用了该子程序不会出错”,则称其为可重入(re ...
- JAVA锁机制-可重入锁,可中断锁,公平锁,读写锁,自旋锁,
如果需要查看具体的synchronized和lock的实现原理,请参考:解决多线程安全问题-无非两个方法synchronized和lock 具体原理(百度) 在并发编程中,经常遇到多个线程访问同一个 ...
- Java多线程系列——深入重入锁ReentrantLock
简述 ReentrantLock 是一个可重入的互斥(/独占)锁,又称为“独占锁”. ReentrantLock通过自定义队列同步器(AQS-AbstractQueuedSychronized,是实现 ...
- synchronized的功能拓展:重入锁(读书笔记)
重入锁可以完全代替synchronized关键字.在JDK5.0的早期版本中,重入锁的性能远远好于synchronized,但是从JDK6.0开始.JDK在synchronized上做了大量的优化. ...
- redis实现分布式锁需要考虑的因素以及可重入锁实现
死锁 错误例子 解决方式 防止死锁 通过设置超时时间 不要使用setnx key expire 20 不能保证原子性 如果setnx程序就挂了 没有执行expire就死锁了 reidis2 ...
随机推荐
- 【学习笔记】可持久化并查集(BZOJ3673)
好久之前就想学了 然后今天恰巧一道题需要用到就学了 前置芝士 1.主席树[可持久化数组] 2.并查集 如果你掌握了前面两个那么这个东西你就会觉得非常沙茶.. 构造 可持久化并查集 = 主席树 + 并 ...
- TJU 4072 3D Birds-Shooting Game
4072. 3D Birds-Shooting Game Time Limit: 3.0 Seconds Memory Limit: 65536K Total Runs: 167 Acce ...
- Python的"random"函数的使用(一)
random.randrange(1,10) 随机产生0~7之间的整数,不包含7. random.sample(range(100), 5) 随机从range(100)中产生5个数,放入一个list. ...
- Window平台下tree 命令使用
WIndow 平台要想打印目录树,可以用cmd工具或者power shell 的tree命令实现 tree 命令格式和参数: TREE [drive:][path] [/F] [/A] /F 显示每个 ...
- mobx学习笔记02——mobx基础语法(class)
新的语法可能不被浏览器支持,可以使用babel转换为浏览器支持的代码格式: 为什么要定义class? js是一门面向对象的编程语言.需要利用类来复用代码,提高编程效率. 需要什么样的class能力? ...
- boost circularBuffer
1. circular buffer has two fundamental properties: (1): The capacity of the circular buffer is const ...
- webpack 图片文件处理loader
目录结构: 引用图片: body { /*background: red;*/ /*background: url("../img/test2.jpg"); 小图片*/ backg ...
- 命令查看当前运行APP的包名和Activity
先用usb链接手机 启动要查看的程序,命令查看当前运行的包名和Activity更清晰. 使用adb shell dumpsys window | findstr mCurrentFocus 命令查看 ...
- Java Web学习总结(2)Servlet(一)
一,Servlet 简介 Java Servlet 是运行在 Web 服务器或应用服务器上的程序,它是作为来自 Web 浏览器或其他 HTTP 客户端的请求和 HTTP 服务器上的数据库或应用程序之间 ...
- JS中关于引用类型数据及函数的参数传递
(JavaScript 中,函数的参数传递方式都是按值传递,没有按引用传递的参数) 一.数据类型 在 javascript 中数据类型可以分为两类: 基本类型值 primitive type,比如Un ...