当前位置: 首页 > news >正文

重入锁+读写锁+公平锁+非公平锁

synchronized关键字可以实现线程间的同步互斥工作。Lock对象锁是一种完成同步互斥工作的一个更优秀机制。它具有比synchronized更为强大的功能,并且有嗅探锁定、多路分支等功能。

重入锁

在需要进行同步的代码部分添加锁定,但不要忘记最后一定要释放锁定,不然会造成锁永远无法释放,其他线程永远进不来的结果。

UseReentrantLock.java

import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

public class UseReentrantLock {
	
	private Lock lock = new ReentrantLock();
	
	public void method1(){
		try {
			lock.lock();//添加锁定
			System.out.println("当前线程:" + Thread.currentThread().getName() + "进入method1..");
			Thread.sleep(1000);
			System.out.println("当前线程:" + Thread.currentThread().getName() + "退出method1..");
			Thread.sleep(1000);
		} catch (InterruptedException e) {
			e.printStackTrace();
		} finally {
			
			lock.unlock();//finally中解除锁定
		}
	}
	
	public void method2(){
		try {
			lock.lock();
			System.out.println("当前线程:" + Thread.currentThread().getName() + "进入method2..");
			Thread.sleep(2000);
			System.out.println("当前线程:" + Thread.currentThread().getName() + "退出method2..");
			Thread.sleep(1000);
		} catch (InterruptedException e) {
			e.printStackTrace();
		} finally {
			
			lock.unlock();
		}
	}
	
	public static void main(String[] args) {

		final UseReentrantLock ur = new UseReentrantLock();
		Thread t1 = new Thread(new Runnable() {
			@Override
			public void run() {
				ur.method1();
				ur.method2();
			}
		}, "t1");

		t1.start();
		
	}
}
Eclipse的console输出:



Lock对象锁中的Condition

在使用synchronized的时候,如果需要多线程间进行协作工作,则需要Object的wait()和notify()、notifyAll()方法进行配合使用。在使用Lock对象锁的时候,可以使用一个新的等待/通知的类,它就是Condition。这个Condition一定是针对具体某一把锁的,也就是只有在锁的基础上才会产生Condition。

UseCondition.java

import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

public class UseCondition {

	private Lock lock = new ReentrantLock();
	private Condition condition = lock.newCondition();
	
	public void method1(){
		try {
			lock.lock();
			System.out.println("当前线程:" + Thread.currentThread().getName() + "进入等待状态..");
			Thread.sleep(3000);
			System.out.println("当前线程:" + Thread.currentThread().getName() + "释放锁..");
			condition.await();	// Object wait
			System.out.println("当前线程:" + Thread.currentThread().getName() +"继续执行...");
		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			lock.unlock();
		}
	}
	
	public void method2(){
		try {
			lock.lock();
			System.out.println("当前线程:" + Thread.currentThread().getName() + "进入..");
			Thread.sleep(3000);
			System.out.println("当前线程:" + Thread.currentThread().getName() + "发出唤醒..");
			condition.signal();		//Object notify
		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			lock.unlock();
		}
	}
	
	public static void main(String[] args) {
		
		final UseCondition uc = new UseCondition();
		Thread t1 = new Thread(new Runnable() {
			@Override
			public void run() {
				uc.method1();
			}
		}, "t1");
		Thread t2 = new Thread(new Runnable() {
			@Override
			public void run() {
				uc.method2();
			}
		}, "t2");
		t1.start();

		t2.start();
	}
	
}
使用Lock对象创建一个Condition对象。main主线程中创建子线程t1、t2,线程t1执行过程中,调用condition.await(),使得线程t1处于阻塞状态。线程t2执行过程中,调用代码condition.signal();,发出唤醒通知,此时t1线程被唤醒,t1线程继续执行。

Eclipse中console输出如下:



多Condition

一个Lock对象可以创建多个Condition进行多线程间的交互,非常的灵活,可以使得部分需要唤醒的线程唤醒,其他线程则继续等待通知。

UseManyCondition.java

import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

public class UseManyCondition {

	private ReentrantLock lock = new ReentrantLock();
	private Condition c1 = lock.newCondition();
	private Condition c2 = lock.newCondition();
	
	public void m1(){
		try {
			lock.lock();
			System.out.println("当前线程:" +Thread.currentThread().getName() + "进入方法m1等待..");
			c1.await();
			System.out.println("当前线程:" +Thread.currentThread().getName() + "方法m1继续..");
		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			lock.unlock();
		}
	}
	
	public void m2(){
		try {
			lock.lock();
			System.out.println("当前线程:" +Thread.currentThread().getName() + "进入方法m2等待..");
			c1.await();
			System.out.println("当前线程:" +Thread.currentThread().getName() + "方法m2继续..");
		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			lock.unlock();
		}
	}
	
	public void m3(){
		try {
			lock.lock();
			System.out.println("当前线程:" +Thread.currentThread().getName() + "进入方法m3等待..");
			c2.await();
			System.out.println("当前线程:" +Thread.currentThread().getName() + "方法m3继续..");
		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			lock.unlock();
		}
	}
	
	public void m4(){
		try {
			lock.lock();
			System.out.println("当前线程:" +Thread.currentThread().getName() + "唤醒..");
			c1.signalAll();
		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			lock.unlock();
		}
	}
	
	public void m5(){
		try {
			lock.lock();
			System.out.println("当前线程:" +Thread.currentThread().getName() + "唤醒..");
			c2.signal();
		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			lock.unlock();
		}
	}
	
	public static void main(String[] args) {
		
		
		final UseManyCondition umc = new UseManyCondition();
		Thread t1 = new Thread(new Runnable() {
			@Override
			public void run() {
				umc.m1();
			}
		},"t1");
		Thread t2 = new Thread(new Runnable() {
			@Override
			public void run() {
				umc.m2();
			}
		},"t2");
		Thread t3 = new Thread(new Runnable() {
			@Override
			public void run() {
				umc.m3();
			}
		},"t3");
		Thread t4 = new Thread(new Runnable() {
			@Override
			public void run() {
				umc.m4();
			}
		},"t4");
		Thread t5 = new Thread(new Runnable() {
			@Override
			public void run() {
				umc.m5();
			}
		},"t5");
		
		t1.start();	
		t2.start();	
		t3.start();	
		

		try {
			Thread.sleep(2000);
		} catch (InterruptedException e) {
			e.printStackTrace();
		}

		t4.start();	
		try {
			Thread.sleep(2000);
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
		t5.start();	
		
	}
	
}
Eclispe的console输出



公平锁与非公平锁

Lock lock=new ReentrantLock(boolean isFair);

lock用法:

tryLock():尝试获得锁,若未被占用返回true,否则返回false

isFair():是否是公平锁

isLocked():是否锁定

getHoldCount():查询当前线程保持此锁的个数,也就是调用lock()的次数

lockInterruptibly():优先响应中断的锁

getQueueLength():返回正在等待获取锁的线程数

getWaitQueueLength():返回等待与锁定相关的给定条件Condition的线程数

hasQueuedThread(Thread thread):查询指定的线程是否正在等待此锁

hasQueuedThreads():查询是否有线程正在等待此锁 

hasWaiters():查询是否有线程正在等待与此锁定有关的conditon条件


读写锁

读写锁ReentrantReadWriteLock,其核心就是实现读写分离的锁,在高并发访问下,尤其是读多写少的情况下,性能要远高于重入锁。之前学synchronized、ReentrantLock时,同一时间内,只能有一个线程进行访问被锁定的代码。而读写锁则不同,其本质是分成两个锁,即读锁、写锁。在读锁下,多个线程可以并发的进行访问,但是在写锁的时候,只能一个一个顺序访问。口诀:读读共享、写写互斥、读写互斥

UseReentrantReadWriteLock.java

import java.util.concurrent.locks.ReentrantReadWriteLock;
import java.util.concurrent.locks.ReentrantReadWriteLock.ReadLock;
import java.util.concurrent.locks.ReentrantReadWriteLock.WriteLock;

public class UseReentrantReadWriteLock {

	private ReentrantReadWriteLock rwLock = new ReentrantReadWriteLock();
	private ReadLock readLock = rwLock.readLock();
	private WriteLock writeLock = rwLock.writeLock();
	
	public void read(){
		try {
			readLock.lock();
			System.out.println("当前线程:" + Thread.currentThread().getName() + "进入...");
			Thread.sleep(3000);
			System.out.println("当前线程:" + Thread.currentThread().getName() + "退出...");
		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			readLock.unlock();
		}
	}
	
	public void write(){
		try {
			writeLock.lock();
			System.out.println("当前线程:" + Thread.currentThread().getName() + "进入...");
			Thread.sleep(3000);
			System.out.println("当前线程:" + Thread.currentThread().getName() + "退出...");
		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			writeLock.unlock();
		}
	}
	
	public static void main(String[] args) {
		
		final UseReentrantReadWriteLock urrw = new UseReentrantReadWriteLock();
		
		Thread t1 = new Thread(new Runnable() {
			@Override
			public void run() {
				urrw.read();
			}
		}, "t1");
		Thread t2 = new Thread(new Runnable() {
			@Override
			public void run() {
				urrw.read();
			}
		}, "t2");
		Thread t3 = new Thread(new Runnable() {
			@Override
			public void run() {
				urrw.write();
			}
		}, "t3");
		Thread t4 = new Thread(new Runnable() {
			@Override
			public void run() {
				urrw.write();
			}
		}, "t4");		
		
		t1.start();
		t2.start();
		t3.start();
		t4.start();
		
	}
}
Eclipse的console输出



相关文章:

  • JVM各组成部分说明+相关参数设置
  • java中垃圾回收算法+垃圾收集器
  • Linux中安装Nexus+Maven
  • Oracle数据库创建实例
  • Nginx中log_format日志格式参数及说明
  • Eclispe SVN 创建分支
  • Eclipse SVN 分支合并+代码冲突处理
  • Java中异常处理机制
  • Linux操作命令总结(六)
  • MySQL中的表连接(外连接、内连接、交叉连接、自连接)
  • location.href的用法
  • MySQL中不相关子查询和相关子查询
  • Linux-eth0 eth0:1 和eth0.1关系、ifconfig以及虚拟IP实现介绍
  • Windows中查看8080端口的占用情况并关闭相关进程
  • Java中使用HttpClient封装post请求和get请求工具方法
  • [nginx文档翻译系列] 控制nginx
  • 【Amaple教程】5. 插件
  • Centos6.8 使用rpm安装mysql5.7
  • CSS 提示工具(Tooltip)
  • Java比较器对数组,集合排序
  • leetcode46 Permutation 排列组合
  • miaov-React 最佳入门
  • mysql_config not found
  • 产品三维模型在线预览
  • 对象管理器(defineProperty)学习笔记
  • 仿天猫超市收藏抛物线动画工具库
  • 你不可错过的前端面试题(一)
  • 微信开放平台全网发布【失败】的几点排查方法
  • 优秀架构师必须掌握的架构思维
  • media数据库操作,可以进行增删改查,实现回收站,隐私照片功能 SharedPreferences存储地址:
  • 哈罗单车融资几十亿元,蚂蚁金服与春华资本加持 ...
  • #[Composer学习笔记]Part1:安装composer并通过composer创建一个项目
  • (10)Linux冯诺依曼结构操作系统的再次理解
  • (第27天)Oracle 数据泵转换分区表
  • (附源码)计算机毕业设计高校学生选课系统
  • (十七)Flask之大型项目目录结构示例【二扣蓝图】
  • (一)基于IDEA的JAVA基础12
  • (转)nsfocus-绿盟科技笔试题目
  • (转)如何上传第三方jar包至Maven私服让maven项目可以使用第三方jar包
  • ./include/caffe/util/cudnn.hpp: In function ‘const char* cudnnGetErrorString(cudnnStatus_t)’: ./incl
  • .NET Core跨平台微服务学习资源
  • .net 无限分类
  • .NET成年了,然后呢?
  • /*在DataTable中更新、删除数据*/
  • @JsonSerialize注解的使用
  • @Transactional类内部访问失效原因详解
  • [ MSF使用实例 ] 利用永恒之蓝(MS17-010)漏洞导致windows靶机蓝屏并获取靶机权限
  • [\u4e00-\u9fa5] //匹配中文字符
  • []AT 指令 收发短信和GPRS上网 SIM508/548
  • [20170713] 无法访问SQL Server
  • [AI]ChatGPT4 与 ChatGPT3.5 区别有多大
  • [Android开源]EasySharedPreferences:优雅的进行SharedPreferences数据存储操作
  • [ANT] 项目中应用ANT
  • [BPU部署教程] 教你搞定YOLOV5部署 (版本: 6.2)
  • [CSDN首发]鱿鱼游戏的具体玩法详细介绍