二十.Synchronized与Lock锁
2021/9/23 23:14:56
本文主要是介绍二十.Synchronized与Lock锁,对大家解决编程问题具有一定的参考价值,需要的程序猿们随着小编来一起学习吧!
Lock锁接口(JUC vital)
实现类
- ReentrantLock(可重入锁)
- ReentrantReadWriteLock.ReadLock
- ReentrantReadWriteLock.WriteLock
底层扩展
- FairSync():公平锁,先来后到
- NonfairSync(default mechanism):非公平锁,可以插队
//源码:构造方法 public ReentrantLock(boolean fair) { sync = fair ? new FairSync() : new NonfairSync(); }
使用步骤
- 1.Lock lock = new ReentrantLock();
- 2.lock.lock();//加锁
- 3.lock.unlock();//解锁
- 代码示例:
package com.cyl.demo01; import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReentrantLock; public class SafeTicketDemo02 { public static void main(String[] args) { //并发,多线程同时操作一个资源类,将资源类丢入线程 Ticket02 ticket = new Ticket02(); //@FunctionInterface 函数式接口 // jdk1.8之后使用lambda表达式简化书写:(parameter)->{code} new Thread(()->{ for (int i = 0; i < 20; i++) ticket.sale(); },"a0").start(); new Thread(()->{ for (int i = 0; i < 20; i++) ticket.sale(); },"a1").start(); new Thread(()->{ for (int i = 0; i < 20; i++) ticket.sale(); },"a2").start(); } } //资源类 //Lock锁 class Ticket02{ // 1.属性,方法(OOP思想) private int ticketNums = 20; Lock lock = new ReentrantLock(); //卖票的方法 public void sale() { lock.lock();//加锁 try {//业务代码 if (ticketNums > 0) { System.out.println(Thread.currentThread().getName()+ "卖出了"+(ticketNums--)+"张票,剩余"+ticketNums); } }catch (Exception e) { e.printStackTrace(); }finally { lock.unlock();//解锁 } } }
##Synchronized与Lock锁的区别
- 1.Synchronized是Java内置的关键字,Lock是Java的一个应用类
- 2.Synchronized无法判断获取锁的状态,Lock可以判断是否获取到了锁
- 3.Synchronized会自动释放锁,Lock需要手动解锁,如果不释放锁,会出现死锁现象
- 4.Synchronized线程b在等待线程a释放锁时,恰好线程a发生阻塞,那么线程b会一直等下去;而Lock锁不一定继续等待,会通过lock.tryLock()方法尝试获取锁
- 5.Synchronized是可重入,非公平锁,不可以中断;Lock是可重入锁,可对锁的状态进行判断,非公平(可以自定义)
- 6.Synchronized适合锁少量的代码同步问题;Lock适合锁大量的同步代码
//源码:构造方法 public ReentrantLock(boolean fair) { sync = fair ? new FairSync() : new NonfairSync(); }
问题重述:生产者和消费者的问题
package com.cyl.PC; /** * 线程之间的通信问题(线程交替执行),等待唤醒,通知唤醒 * 单例模式,生产者和消费者,死锁 * A对num进行+1,告诉B之后,B对num进行-1 * */ public class A { public static void main(String[] args) { Data data = new Data(); new Thread(()->{ for (int i = 0; i < 10; i++) { try { data.increment(); } catch (InterruptedException e) { e.printStackTrace(); } } },"A").start(); new Thread(()->{ for (int i = 0; i < 10; i++) { try { data.decrement(); } catch (InterruptedException e) { e.printStackTrace(); } } },"B").start(); } } //判断是否需要等待,业务,通知 class Data { //数字,资源类 private int num = 0; //+1 public synchronized void increment() throws InterruptedException { if (num != 0) { //等待 this.wait(); } num ++ ; System.out.println(Thread.currentThread().getName()+"==>"+num); //通知其他线程,我+1执行结束了 this.notifyAll(); } //+2 public synchronized void decrement() throws InterruptedException { if (num == 0) { //等待 this.wait(); } num -- ; System.out.println(Thread.currentThread().getName()+"==>"+num); //通知其他线程,我-1执行结束了 this.notifyAll(); } }
那假设线程变得更多呢?(A,B,C,D…)
线程变多,即就产生了虚假唤醒问题,将if判断改为while循环判断即可。
生产者和消费者问题(JUC解决)
- 传统版本:Synchronized wait notify
- JUC版本:Lock await signal
- 代码实现:
class Data02 { //数字,资源类 private int num = 0; Lock lock = new ReentrantLock(); //condition:精准通知和唤醒线程 Condition condition = lock.newCondition(); public void decrement() throws InterruptedException { try { lock.lock(); //业务代码 while (num == 0) { //等待 condition.await(); } //通知其他线程 condition.signalAll(); }catch (Exception e) { e.printStackTrace(); } finally { lock.unlock(); } } }
- 线程间实现顺序通信
package com.cyl.PC; import java.util.concurrent.locks.Condition; import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReentrantLock; /** * 线程间通信,实现顺序执行 * A执行完之后通知B,B执行完之后通知C,C执行完通知A */ public class C { public static void main(String[] args) { Data03 data = new Data03(); new Thread(()->{ for (int i = 0; i < 10; i++) { data.printA(); } },"A").start(); new Thread(()->{ for (int i = 0; i < 10; i++) { data.printB(); } },"B").start(); new Thread(()->{ for (int i = 0; i < 10; i++) { data.printC(); } },"C").start(); } } //资源类 class Data03 {//Lock private Lock lock = new ReentrantLock(); Condition condition01 = lock.newCondition();//同步监视器 Condition condition02 = lock.newCondition(); Condition condition03 = lock.newCondition(); private int num = 1;//1A 2B 3C public void printA() { lock.lock(); try {//业务代码->判断->执行->通知 while(num != 1) { //等待 condition01.await(); } System.out.println(Thread.currentThread().getName()+"AA"); //唤醒指定的线程(B) num = 2; condition02.signal(); } catch (Exception e) { e.printStackTrace(); } finally { lock.unlock(); } } public void printB() { lock.lock(); try {//业务代码->判断->执行->通知 while(num != 2) { condition02.await(); } System.out.println(Thread.currentThread().getName()+"BB"); num = 3; condition03.signal(); } catch (Exception e) { e.printStackTrace(); } finally { lock.unlock(); } } public void printC() { lock.lock(); try {//业务代码->判断->执行->通知 while (num != 3) { condition03.await(); } System.out.println(Thread.currentThread().getName()+"CC"); num = 1; condition01.signal(); } catch (Exception e) { e.printStackTrace(); } finally { lock.unlock(); } } }
这篇关于二十.Synchronized与Lock锁的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!
- 2024-11-23增量更新怎么做?-icode9专业技术文章分享
- 2024-11-23压缩包加密方案有哪些?-icode9专业技术文章分享
- 2024-11-23用shell怎么写一个开机时自动同步远程仓库的代码?-icode9专业技术文章分享
- 2024-11-23webman可以同步自己的仓库吗?-icode9专业技术文章分享
- 2024-11-23在 Webman 中怎么判断是否有某命令进程正在运行?-icode9专业技术文章分享
- 2024-11-23如何重置new Swiper?-icode9专业技术文章分享
- 2024-11-23oss直传有什么好处?-icode9专业技术文章分享
- 2024-11-23如何将oss直传封装成一个组件在其他页面调用时都可以使用?-icode9专业技术文章分享
- 2024-11-23怎么使用laravel 11在代码里获取路由列表?-icode9专业技术文章分享
- 2024-11-22怎么实现ansible playbook 备份代码中命名包含时间戳功能?-icode9专业技术文章分享