当前位置:网站首页>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();
}
}
边栏推荐
- Commands for quickly opening management tools
- UDP通讯应用于多种环境的Demo
- [deep learning] handwritten neural network model preservation
- 第五章神经网络
- 找数组中出现次数最多的数
- Could not load library cudnn_ cnn_ infer64_ 8.dll. Error code 126Please make sure cudnn_ cnn_ infer64_ eight
- vsual studio 2013环境 Udp组播
- Qt char型转QString型 16进制与char型 转 16进制整型
- MySql下载,及安装环境设置
- STM32 DSP库MDK VC5\VC6编译错误: 256, (const float64_t *)twiddleCoefF64_256, armBitRevIndexTableF64_256,
猜你喜欢

第四章 决策树总结

Delete the weight of the head part of the classification network pre training weight and modify the weight name

"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

Xshell远程访问工具

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

Common methods of array

day-7 jvm完结

The problem that the user name and password are automatically filled in when Google / Firefox manages the background new account

《统计学习方法(第2版)》李航 第16章 主成分分析 PCA 思维导图笔记 及 课后习题答案(步骤详细)PCA 矩阵奇异值 第十六章
![OSError: [WinError 127] 找不到指定的程序。Error loading “caffe2_detectron_ops.dll“ or one of its dependencies](/img/1d/4c9924c20f697011f0e9cda6616c12.png)
OSError: [WinError 127] 找不到指定的程序。Error loading “caffe2_detectron_ops.dll“ or one of its dependencies
随机推荐
删除分类网络预训练权重的的head部分的权重以及修改权重名称
What do programmers often mean by API? What are the API types?
opencv读取avi视频报错:number < max_number in function ‘icvExtractPattern
[raspberry pie 4B] VII. Summary of remote login methods for raspberry pie xshell, putty, vncserver, xrdp
UDP通讯应用于多种环境的Demo
JS star scoring effect
Machine learning (zhouzhihua) Chapter 2 model selection and evaluation notes learning experience
[activiti] activiti introduction
tensorflow和pytorch框架的安装以及cuda踩坑记录
Positional argument after keyword argument
《统计学习方法(第2版)》李航 第15章 奇异值分解 SVD 思维导图笔记 及 课后习题答案(步骤详细)SVD 矩阵奇异值 十五章
AD1256
[activiti] process example
Problems in SSM project configuration, various dependencies, etc. (for personal use)
Raspberry pie is of great use. Use the campus network to build a campus local website
Target detection tagged data enhancement code
day1-jvm+leetcode
Numpy cheatsheet
【深度学习】手写神经网络模型保存
LSTM神经网络