java多线程并发中使用Lockers类将多线程共享资源锁定
发布时间:2021-11-14 11:08:37
package com.yao;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReadWriteLock;
import java.util.concurrent.locks.ReentrantLock;
import java.util.concurrent.locks.ReentrantReadWriteLock;
/**
* Lockers
* 在多线程编程里面一个重要的概念是锁定,如果一个资源是多个线程共享的,为了保证数据的完整性,
* 在进行事务性操作时需要将共享资源锁定,这样可以保证在做事务性操作时只有一个线程能对资源进行操作,
* 从而保证数据的完整性。在5.0以前,锁定的功能是由Synchronized关键字来实现的。
*/
public class Lockers {
/**
* 测试Lock的使用。在方法中使用Lock,可以避免使用Synchronized关键字。
*/
public static class LockTest {
Lock lock = new ReentrantLock();// 锁
double value = 0d; // 值
int addtimes = 0;
/**
* 增加value的值,该方法的操作分为2步,而且相互依赖,必须实现在一个事务中
* 所以该方法必须同步,以前的做法是在方法声明中使用Synchronized关键字。
*/
public void addValue(double v) {
lock.lock();// 取得锁
System.out.println("LockTest to addValue: " + v + " "
+ System.currentTimeMillis());
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
}
this.value += v;
this.addtimes++;
lock.unlock();// 释放锁
}
public double getValue() {
return this.value;
}
}
public static void testLockTest() throws Exception{
final LockTest lockTest = new LockTest();
// 新建任务1,调用lockTest的addValue方法
Runnable task1 = new Runnable(){
public void run(){
lockTest.addValue(55.55);
}
};
// 新建任务2,调用lockTest的getValue方法
Runnable task2 = new Runnable(){
public void run(){
System.out.println("value: " + lockTest.getValue());
}
};
// 新建任务执行服务
ExecutorService cachedService = Executors.newCachedThreadPool();
Future future = null;
// 同时执行任务1三次,由于addValue方法使用了锁机制,所以,实质上会顺序执行
for (int i=0; i<3; i++){
future = cachedService.submit(task1);
}
// 等待最后一个任务1被执行完
future.get();
// 再执行任务2,输出结果
future = cachedService.submit(task2);
// 等待任务2执行完后,关闭任务执行服务
future.get();
cachedService.shutdownNow();
}
/**
* ReadWriteLock内置两个Lock,一个是读的Lock,一个是写的Lock。
* 多个线程可同时得到读的Lock,但只有一个线程能得到写的Lock,
* 而且写的Lock被锁定后,任何线程都不能得到Lock。ReadWriteLock提供的方法有:
* readLock(): 返回一个读的lock
* writeLock(): 返回一个写的lock, 此lock是排他的。
* ReadWriteLockTest很适合处理类似文件的读写操作。
* 读的时候可以同时读,但不能写;写的时候既不能同时写也不能读。
*/
public static class ReadWriteLockTest{
// 锁
ReadWriteLock lock = new ReentrantReadWriteLock();
// 值
double value = 0d;
int addtimes = 0;
/**
* 增加value的值,不允许多个线程同时进入该方法
*/
public void addValue(double v) {
// 得到writeLock并锁定
Lock writeLock = lock.writeLock();
writeLock.lock();
System.out.println("ReadWriteLockTest to addValue: " + v + " "
+ System.currentTimeMillis());
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
}
try {
// 做写的工作
this.value += v;
this.addtimes++;
} finally {
// 释放writeLock锁
writeLock.unlock();
}
}
/**
* 获得信息。当有线程在调用addValue方法时,getInfo得到的信息可能是不正确的。
* 所以,也必须保证该方法在被调用时,没有方法在调用addValue方法。
*/
public String getInfo() {
// 得到readLock并锁定
Lock readLock = lock.readLock();
readLock.lock();
System.out.println("ReadWriteLockTest to getInfo "
+ System.currentTimeMillis());
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
}
try {
// 做读的工作
return this.value + " : " + this.addtimes;
} finally {
// 释放readLock
readLock.unlock();
}
}
}
public static void testReadWriteLockTest() throws Exception{
final ReadWriteLockTest readWriteLockTest = new ReadWriteLockTest();
// 新建任务1,调用lockTest的addValue方法
Runnable task_1 = new Runnable(){
public void run(){
readWriteLockTest.addValue(55.55);
}
};
// 新建任务2,调用lockTest的getValue方法
Runnable task_2 = new Runnable(){
public void run(){
System.out.println("info: " + readWriteLockTest.getInfo());
}
};
// 新建任务执行服务
ExecutorService cachedService_1 = Executors.newCachedThreadPool();
Future future_1 = null;
// 同时执行5个任务,其中前2个任务是task_1,后两个任务是task_2
for (int i=0; i<2; i++){
future_1 = cachedService_1.submit(task_1);
}
for (int i=0; i<2; i++){
future_1 = cachedService_1.submit(task_2);
}
// 最后一个任务是task_1
future_1 = cachedService_1.submit(task_1);
// 这5个任务的执行顺序应该是:
// 第一个task_1先执行,第二个task_1再执行;这是因为不能同时写,所以必须等。
// 然后2个task_2同时执行;这是因为在写的时候,就不能读,所以都等待写结束,
// 又因为可以同时读,所以它们同时执行
// 最后一个task_1再执行。这是因为在读的时候,也不能写,所以必须等待读结束后,才能写。
// 等待最后一个task_2被执行完
future_1.get();
cachedService_1.shutdownNow();
}
public static void main(String[] args) throws Exception{
Lockers.testLockTest();
System.out.println("---------------------");
Lockers.testReadWriteLockTest();
}
}


猜你喜欢
- 目录一、事出有因二、解决方案困境三、柳暗花明,终级解决方案第一种实现方案第二种实现方案第三种实现方案四、引发的思考一、事出有因最近有一个场景
- 本文实例讲述了Android实现完整游戏循环的方法。分享给大家供大家参考。具体如下:1. DroidzActivity.java:packa
- 一、登录认证基于过滤器链Spring Security的登录验证流程核心就是过滤器链。当一个请求到达时按照过滤器链的顺序依次进行处理,通过所
- 上一篇实现了移动端微信消息界面功能,以此为基础继续完善服务端功能服务端微信消息页实现微信消息界面的实现,和登录,注册是类似的,无非就是接受客
- Android Q 禁止获取 IMEI 和设备序列号;官方的解决方案是这样:https://developer.android.com/tr
- 一、前言在Java编码中,我们经常会遇到List与数组的转换,包括对象List与对象数组的转换,以及对象List与基本数据类型数组的转换,下
- 本文实例讲述了C#多线程处理多个队列数据的方法。分享给大家供大家参考。具体实现方法如下:using System;using System.
- 最近学习Spring,一直不太明白Srping的切面编程中的的argNames的含义,经过学习研究后,终于明白,分享一下需要监控的类:pac
- springboot初始化器新建项目项目结构idea工具类中初始化本地git仓库选择当前项目目录即可工具类由VCS变成了Gitadd 到缓存
- 本文实例为大家分享了Java实现UDP多线程在线咨询,供大家参考,具体内容如下1.发送的线程import java.io.BufferedR
- 前文传送门:Netty启动流程服务端channel初始化注册多路复用回到上一小节的代码:final ChannelFuture initAn
- 本文实例讲述了C#编程实现获取文件夹中所有文件的文件名。分享给大家供大家参考,具体如下:想实现这样一个功能:批量修改一个目录所有jpg文件的
- BeanFactory接口:IoC容器的顶级接口,是IoC容器的最基础实现,也是访问Spring容器的根接口,负责对bean的创建,访问等工
- 如下所示:import java.util.*;public class Main{public static void main(Stri
- java 多线程的三种构建方法继承Thread类创建线程类public class Thread extends Object
- 本文将介绍一段实例代码,来讲解利用正则表达式使C#判断输入日期格式是否正确的方法。希望这段代码能对大家有所帮助。 通常我们在用C#
- 目录依赖引入PowerMockito的使用使用mockito来mock实例mock对Redis的静态调用mock单例类mock私有方法Pow
- 简介本文用示例介绍java的Duration的用法。Duration和Period说明Duration类通过秒和纳秒相结合来描述一个时间量,
- 概述在实际项目开发中如果需要支持多语言,我们需要整理项目中所有的字符串并翻译成对应的语种放在相应的文件夹下,就像这样最让我们头痛的是我们得一
- 前言之前写过一篇介绍flutter集成到Android工程的文章,这次总结记录一下自己把flutter集成到iOS的流程,以及遇到的问题以及