当前位置:网站首页>JUC并发编程基础(6)--Lock锁
JUC并发编程基础(6)--Lock锁
2022-07-24 05:21:00 【aMythhhhh】
LOCK接口
synchronized关键字回顾
- 修饰一个同步语句代码块,作用范围是大括号{}括起来的代码,作用对象是调用这个代码块的对象。
- 修饰一个方法,被修饰的方法称为同步方法,其作用范围是整个方法,作用的对象是调用这个方法的对象。
- 修饰一个静态方法。
- 修饰一个类。
多线程编程步骤(上)
创建一个资源类,定义属性和操作方法 (高内聚低耦合思想)
在资源类操作方法
- 判断
- 干活
- 通知
创建多个线程,调用资源类的操作方法
操作实例:
package com.amyth.JavaEE;
//创建资源类
class Ticket{
private int number = 30;
//加上synchronized修饰方法
public synchronized void sale(){
if(number > 0 ) {
System.out.println(Thread.currentThread().getName() + "卖出1张票,剩余:" + (number--) + "张");
}else{
System.out.println(Thread.currentThread().getName() + "卖出0张票,剩余:0没票啦!!!");
}
}
}
public class SyncTest {
public static void main(String[] args) {
//将资源创建出来
Ticket ticket = new Ticket();
new Thread(new Runnable() {
@Override
public void run() {
for (int i=0; i<30;i++)
{
ticket.sale();
}
}
},"AA").start();
new Thread(new Runnable() {
@Override
public void run() {
for (int i=0; i<40;i++)
{
ticket.sale();
}
}
},"BB").start();
new Thread(new Runnable() {
@Override
public void run() {
for (int i=0; i<40;i++)
{
ticket.sale();
}
}
},"CC").start();
}
}
Lock和Synchronized的区别
Lock锁实现了比使用同步方法和语句可以获得更广泛的锁操作,提供了更多功能。
- Lock不是JAVA内置的,Synchronized是关键字,有内置特性,Lock是一个类,通过这个类可以实现同步访问。
- 最大的不同在于,Lock需要手动释放锁,否则可能会出现“死锁”现象,而Synchronized不需要,是自动释放。
利用可重入锁:ReentrantLock重写上述售票案例
package com.amyth.JavaEE;
import java.util.concurrent.locks.ReentrantLock;
//创建资源类
class Ticket{
private int number = 100;
//使用可重用锁ReentrantLock
private final ReentrantLock lock = new ReentrantLock();
public void sale(){
lock.lock(); //上锁
try{
if(number > 0 ) {
System.out.println(Thread.currentThread().getName() + "卖出1张票,剩余:" + (number--) + "张");
}else{
System.out.println(Thread.currentThread().getName() + "卖出0张票,剩余:0没票啦!!!");
}
}finally {
lock.unlock(); //解锁
}
}
}
public class SyncTest {
public static void main(String[] args) {
//将资源创建出来
Ticket ticket = new Ticket();
//这里使用了lambda表达式简化了代码
//匿名类实现的接口使用了java.lang.FunctionalInterface注解,且只有一个待实现的抽象接口方法
new Thread(() -> {
for (int i=0; i<30;i++)
{
ticket.sale();
}
},"AA").start();
new Thread(() -> {
for (int i=0; i<30;i++)
{
ticket.sale();
}
},"BB").start();
new Thread(() -> {
for (int i=0; i<30;i++)
{
ticket.sale();
}
},"CC").start();
}
}
- LOCK能让等待锁的线程响应中断,synchronized不行,等待的线程会一直等下去。
- 通过LOCK可以知道是否获取锁,关键字无法做到。
- LOCK可以提高多个线程进行读操作的效率。
总的来说,在资源竞争激烈的环境中,LOCK的性能非常非常好!
通过synchronized实现进程间通信的方法 number+1-1:
package com.amyth.JavaEE;
//资源类创建
class Share{
private int number = 0;
public synchronized void incr() throws InterruptedException {
//资源类中操作方法
if(number!=0){
this.wait();
}
number++;
System.out.println("Thread number = "+number);
this.notify();
}
public synchronized void decr() throws InterruptedException {
if (number==0){
this.wait();
}
number--;
System.out.println("Thread number = "+number);
this.notify();
}
}
public class ThreadDemo1 {
public static void main(String[] args) {
Share share = new Share();
new Thread(()->{
for(int i =0;i<=10;i++){
try {
share.incr();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
},"ADD").start();
new Thread(()->{
for(int i =0;i<=10;i++){
try {
share.decr();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
},"Decr").start();
}
}
虚假唤醒问题实例:当线程数超过2个之后,使用if判断就可能出现虚假唤醒问题
package com.amyth.JavaEE;
//资源类创建
class Share{
private int number = 0;
public synchronized void incr() throws InterruptedException {
//资源类中操作方法
if(number!=0){
this.wait();
}
number++;
System.out.println("Thread number = "+number);
this.notifyAll();
}
public synchronized void decr() throws InterruptedException {
if (number==0){
this.wait();
}
number--;
System.out.println("Thread number = "+number);
this.notifyAll();
}
}
public class ThreadDemo1 {
public static void main(String[] args) {
Share share = new Share();
new Thread(()->{
for(int i =0;i<=10;i++){
try {
share.incr();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
},"ADD").start();
new Thread(()->{
for(int i =0;i<=10;i++){
try {
share.decr();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
},"Decr").start();
new Thread(()->{
for(int i =0;i<=10;i++){
try {
share.incr();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
},"CC").start();
new Thread(()->{
for(int i =0;i<=10;i++){
try {
share.decr();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
},"DD").start();
}
}

此时结果中就出现1、0之外的数字,这就是虚假唤醒情况。
具体分析:
AA线程+1之后 num=1 唤醒其余线程
此时可能CC抢到了线程 通过if判断 num!=0 就进入了wait
…
经过一系列这种操作,一旦别的线程再次唤醒CC线程,此时就会执行wait之后的代码
因为这是基于wait方法在哪里睡着就在哪里醒来的特点,因此if判断只一次有效,第二次被唤醒就不经过if
解决办法就是使用while循环进行判断,睡着之后醒来又会在循环中再进行判断。
使用LOCK锁实现上述示例
package com.amyth.JavaEE;
import javax.naming.NameNotFoundException;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
//创建资源类
class Numbers{
private int number=0;
private Lock lock= new ReentrantLock();
private Condition condition = lock.newCondition();
//+1
public void incr() throws InterruptedException {
lock.lock();
//判断
try{
while(number !=0){
condition.await();
}
//干活
number++;
System.out.println("number +1 :"+number);
//通知
condition.signalAll();
}finally {
lock.unlock();
}
}
//-1
public void decr() throws InterruptedException {
lock.lock();
//判断
try{
while(number ==0){
condition.await();
}
//干活
number--;
System.out.println("number -1 :"+number);
//通知
condition.signalAll();
}finally {
lock.unlock();
}
}
}
public class ThreadDemo2 {
public static void main(String[] args) {
Numbers numbers = new Numbers();
new Thread(() -> {
for (int i =0;i<=10;i++){
try {
numbers.incr();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
},"AA").start();
new Thread(() -> {
for (int i =0;i<=10;i++){
try {
numbers.decr();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
},"BB").start();
}
}
边栏推荐
- 《统计学习方法(第2版)》李航 第14章 聚类方法 思维导图笔记 及 课后习题答案(步骤详细) k-均值 层次聚类 第十四章
- [deep learning] teach you to write "handwritten digit recognition neural network" hand in hand, without using any framework, pure numpy
- STM32 DSP库MDK VC5\VC6编译错误: 256, (const float64_t *)twiddleCoefF64_256, armBitRevIndexTableF64_256,
- Connect CRM system and effect advertising, help enterprises with precision marketing, and help enterprises with precision marketing
- day1-jvm+leetcode
- Two architectures of data integration: ELT and ETL
- 《剑指Offer》 二维数组的查找 C语言版本
- vsual studio 2013环境 Udp组播
- 西瓜书/南瓜书--第1,2章总结
- OSError: [WinError 127] 找不到指定的程序。Error loading “caffe2_detectron_ops.dll“ or one of its dependencies
猜你喜欢

"Statistical learning methods (2nd Edition)" Li Hang Chapter 14 clustering method mind map notes and after-school exercise answers (detailed steps) K-means hierarchical clustering Chapter 14
![[activiti] process example](/img/77/63d7d1ea8c634fb3741383f40f38e7.png)
[activiti] process example

"Statistical learning methods (2nd Edition)" Li Hang Chapter 17 latent semantic analysis LSA LSI mind mapping notes and after-school exercise answers (detailed steps) Chapter 17

day1-jvm+leetcode

【数据库系统原理】第五章 代数和逻辑查询语言:包、扩展操作符、关系逻辑、关系代数与Datalog

第四章 决策树总结

《统计学习方法(第2版)》李航 第15章 奇异值分解 SVD 思维导图笔记 及 课后习题答案(步骤详细)SVD 矩阵奇异值 十五章
![[MYCAT] MYCAT installation](/img/52/2f77ed64b2ed4e9297acaa8362e194.png)
[MYCAT] MYCAT installation

【USB Host】STM32H7 CubeMX移植带FreeRTOS的USB Host读取U盘,USBH_Process_OS卡死问题,有个值为0xA5A5A5A5

【FatFs】手动移植FatFs,将SRAM虚拟U盘
随机推荐
day-7 jvm完结
删除分类网络预训练权重的的head部分的权重以及修改权重名称
数据归一化
[activiti] group task
[activiti] activiti process engine configuration class
用指针访问二维数组
顺序栈 C语言 进栈 出栈 遍历
Raspberry pie is of great use. Use the campus network to build a campus local website
《统计学习方法(第2版)》李航 第17章 潜在语义分析 LSA LSI 思维导图笔记 及 课后习题答案(步骤详细)第十七章
Numpy cheatsheet
day3-jvm+排序总结
Points for attention in adding spp module to the network
Numpy cheatsheet
CRC-16 Modbus代码
"Statistical learning methods (2nd Edition)" Li Hang Chapter 16 principal component analysis PCA mind map notes and after-school exercise answers (detailed steps) PCA matrix singular value Chapter 16
Jupyter notebook选择conda环境
jupyter notebook一直自动重启(The kernel appears to have died. It will restart automatically.)
Qt新建工程简介
Typora installation package in November 2021, the last free version of the installation package to download v13.6.1
解决ModularNotFoundError: No module named “cv2.aruco“