java 并发多线程显式锁概念简介 什么是显式锁 多线程下篇(一)
示例回顾
package test1;
import java.util.LinkedList;
/**
* 消息队列MessageQueue 测试
*/
public class T14 {
public static void main(String[] args) {
final RefactorMessageQueue mq = new RefactorMessageQueue(5);
System.out.println("***************task begin***************");
//创建生产者线程并启动
for (int i = 0; i < 20; i++) {
new Thread(() -> {
while (true) {
mq.set(new Message());
}
}, "producer"+i).start();
}
//创建消费者线程并启动
new Thread(() -> {
while (true) {
mq.get();
}
}, "consumer").start();
}
}
/**
* 消息队列
*/
class RefactorMessageQueue {
/**
* 队列最大值
*/
private final int max;
/*
* 锁
* */
private final byte[] lock = new byte[1];
/**
* final确保发布安全
*/
final LinkedList<Message> messageQueue = new LinkedList<>();
/**
* 构造函数默认队列大小为10
*/
public RefactorMessageQueue() {
max = 10;
}
/**
* 构造函数设置队列大小
*/
public RefactorMessageQueue(int x) {
max = x;
}
public void set(Message message) {
synchronized (lock) {
//如果已经大于队列个数,队列满,进入等待
while (messageQueue.size() > max) {
try {
System.out.println(Thread.currentThread().getName() + " : queue is full ,waiting...");
lock.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
//如果队列未满,生产消息,随后通知lock上的等待线程
//每一次的消息生产,都会通知消费者
System.out.println(Thread.currentThread().getName() + " : add a message");
messageQueue.addLast(message);
lock.notifyAll();
}
}
public void get() {
synchronized (lock) {
//如果队列为空,进入等待,无法获取消息
while (messageQueue.isEmpty()) {
try {
System.out.println(Thread.currentThread().getName() + " : queue is empty ,waiting...");
lock.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
//队列非空时,读取消息,随后通知lock上的等待线程
//每一次的消息读取,都会通知生产者
System.out.println(Thread.currentThread().getName() + " : get a message");
messageQueue.removeFirst();
lock.notifyAll();
}
}
}
- synchronized关键字
- 监视器方法
显式锁逻辑
Lock l = ...;
l.lock();
try {
// access the resource protected by this lock
} finally {
l.unlock();
}
package test2;
import java.util.LinkedList;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
public class T26 {
public static void main(String[] args) {
final RefactorMessageQueue mq = new RefactorMessageQueue(5);
System.out.println("***************task begin***************");
//创建生产者线程并启动
for (int i = 0; i < 20; i++) {
new Thread(() -> {
while (true) {
mq.set(new Message());
}
}, "producer" + i).start();
}
//创建消费者线程并启动
new Thread(() -> {
while (true) {
mq.get();
}
}, "consumer").start();
}
/**
* 消息队列中存储的消息
*/
static class Message {
}
/**
* 消息队列
*/
static class RefactorMessageQueue {
/**
* 队列最大值
*/
private final int max;
/*
* 锁
* */
private final Lock lock = new ReentrantLock();
/**
* 条件变量
*/
private final Condition condition = lock.newCondition();
/**
* final确保发布安全
*/
final LinkedList<Message> messageQueue = new LinkedList<>();
/**
* 构造函数默认队列大小为10
*/
public RefactorMessageQueue() {
max = 10;
}
/**
* 构造函数设置队列大小
*/
public RefactorMessageQueue(int x) {
max = x;
}
public void set(Message message) {
lock.lock();
try {
//如果已经大于队列个数,队列满,进入等待
while (messageQueue.size() > max) {
try {
System.out.println(Thread.currentThread().getName() + " : queue is full ,waiting...");
condition.await();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
//如果队列未满,生产消息,随后通知lock上的等待线程
//每一次的消息生产,都会通知消费者
System.out.println(Thread.currentThread().getName() + " : add a message");
messageQueue.addLast(message);
condition.signalAll();
} finally {
}
lock.unlock();
}
public void get() {
lock.lock();
try {
//如果队列为空,进入等待,无法获取消息
while (messageQueue.isEmpty()) {
try {
System.out.println(Thread.currentThread().getName() + " : queue is empty ,waiting...");
condition.await();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
//队列非空时,读取消息,随后通知lock上的等待线程
//每一次的消息读取,都会通知生产者
System.out.println(Thread.currentThread().getName() + " : get a message");
messageQueue.removeFirst();
condition.signalAll();
} finally {
lock.unlock();
}
}
}
}
/*
* 锁
* */
private final Lock lock = new ReentrantLock();
/**
* 条件变量
*/
private final Condition condition = lock.newCondition();
- 使用lock.lock();以及lock.unlock(); 替代了synchronized(lock)
- 使用condition的await和signalAll方法替代了lock.wait()和 lock.notifyAll
package test2;
import java.util.LinkedList;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock; public class T27 {
public static void main(String[] args) {
final RefactorMessageQueue mq = new RefactorMessageQueue(5);
System.out.println("***************task begin***************");
//创建生产者线程并启动
for (int i = 0; i < 20; i++) {
new Thread(() -> {
while (true) {
mq.set(new Message());
}
}, "producer" + i).start();
}
//创建消费者线程并启动
new Thread(() -> {
while (true) {
mq.get();
}
}, "consumer").start();
}
/**
* 消息队列中存储的消息
*/
static class Message {
}
/**
* 消息队列
*/
static class RefactorMessageQueue {
/**
* 队列最大值
*/
private final int max;
/*
* 锁
* */
private final Lock lock = new ReentrantLock();
/**
* 条件变量,用于消费者,非空即可消费
*/
private final Condition notEmptyCondition = lock.newCondition();
/**
* 条件变量,用于生产者,非满即可生产
*/
private final Condition notFullCondition = lock.newCondition();
/**
* final确保发布安全
*/
final LinkedList<Message> messageQueue = new LinkedList<>();
/**
* 构造函数默认队列大小为10
*/
public RefactorMessageQueue() {
max = 10;
}
/**
* 构造函数设置队列大小
*/
public RefactorMessageQueue(int x) {
max = x;
}
public void set(Message message) {
lock.lock();
try {
//如果已经大于队列个数,队列满,进入等待
while (messageQueue.size() > max) {
try {
System.out.println(Thread.currentThread().getName() + " : queue is full ,waiting...");
//如果满了,生产者在“非满”这个条件上等待
notFullCondition.await();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
//如果队列未满,生产消息,随后通知lock上的等待线程
//每一次的消息生产,都会通知消费者
System.out.println(Thread.currentThread().getName() + " : add a message");
messageQueue.addLast(message);
//生产后,增加了消息,非空条件满足,需要唤醒消费者
notEmptyCondition.signalAll();
} finally {
}
lock.unlock();
}
public void get() {
lock.lock();
try {
//如果队列为空,进入等待,无法获取消息
while (messageQueue.isEmpty()) {
try {
System.out.println(Thread.currentThread().getName() + " : queue is empty ,waiting...");
//如果空了,消费者需要在“非空”条件上等待
notEmptyCondition.await();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
//队列非空时,读取消息,随后通知lock上的等待线程
//每一次的消息读取,都会通知生产者
System.out.println(Thread.currentThread().getName() + " : get a message");
messageQueue.removeFirst();
//消费后,减少了消息,所以非满条件满足,需要唤醒生产者
notFullCondition.signalAll();
} finally {
lock.unlock();
}
}
}
}
总结
java 并发多线程显式锁概念简介 什么是显式锁 多线程下篇(一)的更多相关文章
- Java并发编程(三)概念介绍
在构建稳健的并发程序时,必须正确使用线程和锁.但是这终归只是一些机制.要编写线程安全的代码,其核心在于要对状态访问操作进行管理,特别是对共享的(Shared)和可变的(Mutable)状态的访问. 对 ...
- java并发里的一些基础概念
转载自:https://my.oschina.net/hosee/blog/597934: 摘要: 本系列基于炼数成金课程,为了更好的学习,做了系列的记录. 本文主要介绍 1.高并发的概念,为以后系列 ...
- java并发系列(四)-----源码角度彻底理解ReentrantLock(重入锁)
1.前言 ReentrantLock可以有公平锁和非公平锁的不同实现,只要在构造它的时候传入不同的布尔值,继续跟进下源码我们就能发现,关键在于实例化内部变量sync的方式不同,如下所示: /** * ...
- Java并发基础类AbstractQueuedSynchronizer的实现原理简介
1.引子 Lock接口的主要实现类ReentrantLock 内部主要是利用一个Sync类型的成员变量sync来委托Lock锁接口的实现,而Sync继承于AbstractQueuedSynchroni ...
- Java并发编程原理与实战三十九:JDK8新增锁StampedLock详解
1.StampedLock是做什么的? ----->它是ReentrantReadWriteLock 的增强版,是为了解决ReentrantReadWriteLock的一些不足. 2.Ree ...
- Java并发编程原理与实战十七:AQS实现重入锁
一.什么是重入锁 可重入锁就是当前持有锁的线程能够多次获取该锁,无需等待 二.什么是AQS AQS是JDK1.5提供的一个基于FIFO等待队列实现的一个用于实现同步器的基础框架,这个基础框架的重要性可 ...
- Java并发编程——线程的基本概念和创建
一.线程的基本概念: 1.什么是进程.什么是是线程.多线程? 进程:一个正在运行的程序(程序进入内存运行就变成了一个进程).比如QQ程序就是一个进程. 线程:线程是进程中的一个执行单元,负责当前进程中 ...
- java并发编程基础 --- 4.1线程简介
一.线程简介 什么是线程: 现在操作系统在运行一个程序时,会为其创建一个进程.例如,启动一个java程序,操作系统就会创建一个java进程.现代操作系统调度的最小单元是线程,也叫轻量级进程,在一个进程 ...
- 并发系列2:Java并发的基石,volatile关键字、synchronized关键字、乐观锁CAS操作
由并发大师Doug Lea操刀的并发包Concurrent是并发编程的重要包,而并发包的基石又是volatile关键字.synchronized关键字.乐观锁CAS操作这些基础.因此了解他们的原理对我 ...
随机推荐
- BZOJ_2039_[2009国家集训队]employ人员雇佣_ 最小割
BZOJ_2039_[2009国家集训队]employ人员雇佣_ 最小割 Description 作为一个富有经营头脑的富翁,小L决定从本国最优秀的经理中雇佣一些来经营自己的公司.这些经理相互之间合作 ...
- BZOJ_4773_负环_倍增弗洛伊德
BZOJ_4773_负环 Description 在忘记考虑负环之后,黎瑟的算法又出错了.对于边带权的有向图 G = (V, E),请找出一个点数最小的环,使得 环上的边权和为负数.保证图中不包含重边 ...
- 汽车之家汽车品牌Logo信息抓取 DotnetSpider实战[三]
一.正题前的唠叨 第一篇实战博客,阅读量1000+,第二篇,阅读量200+,两篇文章相差近5倍,这个差异真的令我很费劲,截止今天,我一直在思考为什么会有这么大的差距,是因为干货变少了,还是什么原因,一 ...
- Scala 枚举介绍及深入应用
本文详细地总结了Scala枚举的几种实现方式,对我们更好地进行函数式编程有很好地指导和帮助. Scala 枚举示例和特性 枚举(Enumerations)是一种语言特性,对于建模有限的实体集来说特别有 ...
- 【Maven篇】---解决Maven线上部署java.lang.ClassNotFoundException和no main manifest attribute解决方法
一.前述 maven 线上部署的话会出现一些问题比如java.lang.ClassNotFoundException或者no main manifest attribute的话,是因为maven 配置 ...
- 有道云笔记MarkDown 插入图片
前言: 在网上找了很多有道云笔记的markdown笔记如何插入本地图片,试了好几种方式都是一时可以显示而已,只要电脑重启或者换终端查看就无法显示图片了.网上常用的方法无非两种有效:github.博客. ...
- github下载和上传项目
git下载和上传项目 下载: git clone +地址 上传: 1.git init 在当前项目的目录中生成本地的git管理(多一个.git文件夹,为隐藏文件) 2.git add .(注意最后面有 ...
- 外网访问FTP出错200 Type set to A
打开IE浏览器,在intenet选项里的高级==> 这里没有勾就对了!
- 『随笔』.Net 底层 数组[] 的 基本设计探秘 512 子数组
static void Main(string[] args) { Console.ReadKey(); //初始化数组 不会立即开辟内存字节, 只有实际给数组赋值时 才会开辟内存 // //猜测数组 ...
- redis-win-server 正确启动方式
C:\Users\Administrator\Desktop\Redis-x64-2.8.2402\redis-server.exe C:\Users\Administrator\Desktop\R ...