当前位置:网站首页>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();
}
}
边栏推荐
- "Statistical learning methods (2nd Edition)" Li Hang Chapter 13 introduction to unsupervised learning mind map notes
- Machine learning (Zhou Zhihua) Chapter 3 Notes on learning linear models
- Detailed discussion on data synchronization tools ETL, ELT, reverse ETL
- 《统计学习方法(第2版)》李航 第15章 奇异值分解 SVD 思维导图笔记 及 课后习题答案(步骤详细)SVD 矩阵奇异值 十五章
- C语言链表(创建、遍历、释放、查找、删除、插入一个节点、排序,逆序)
- 找数组中出现次数最多的数
- 精确计算时间延迟VxWorks 时间戳 详解
- Signals and systems: Hilbert transform
- 列表写入txt直接去除中间的逗号
- UDP通讯应用于多种环境的Demo
猜你喜欢

Learning rate optimization strategy

学习率余弦退火衰减之后的loss

如何在网页上下载视频
![[USB host] stm32h7 cubemx porting USB host with FreeRTOS to read USB disk, usbh_ Process_ The OS is stuck. There is a value of 0xa5a5a5](/img/be/b7723920f0e81e8699bb26dd1c0fe5.png)
[USB host] stm32h7 cubemx porting USB host with FreeRTOS to read USB disk, usbh_ Process_ The OS is stuck. There is a value of 0xa5a5a5

MySql下载,及安装环境设置
![[activiti] activiti introduction](/img/17/bd8f6fd8dd8918a984ca0a3793ec0b.jpg)
[activiti] activiti introduction

day6-jvm

Typora 安装包2021年11月最后一次免费版本的安装包下载V13.6.1
![[activiti] Introduction to activiti](/img/99/e973279d661960853b3af69a7e8ef2.png)
[activiti] Introduction to activiti

树莓派大用处,利用校园网搭建一个校园局域网站
随机推荐
[activiti] activiti environment configuration
In GCC__ attribute__ ((constructor) and__ attribute__ ((destructor)).
Points for attention in adding spp module to the network
DeepSort 总结
Erp+rpa opens up the enterprise information island, and the enterprise benefits are doubled
YOLOv5学习总结(持续更新)
Signals and systems: Hilbert transform
《统计学习方法(第2版)》李航 第15章 奇异值分解 SVD 思维导图笔记 及 课后习题答案(步骤详细)SVD 矩阵奇异值 十五章
JSON. Dumps() function parsing
精确计算时间延迟VxWorks 时间戳 详解
vsual studio 2013环境 Udp组播
Chapter IV decision tree summary
day6-jvm
CRC-16 Modbus代码
Two architectures of data integration: ELT and ETL
Test whether the label and data set correspond after data enhancement
JVM系统学习
opencv读取avi视频报错:number < max_number in function ‘icvExtractPattern
Machine learning (zhouzhihua) Chapter 5 notes on neural network learning
主成分分析计算步骤