学习预告:本节课只是概要,通过本次课程需要掌握学会使用Lock锁,理解lock锁与Synchronized区别,以及在Synchronized版本和LoKC下消费者和生产者!
3、Lock锁
学会使用Lock锁(温馨提示:先看完视频,然后再进行去看代码,进行练习实操哦)
传统同步
package com.coding.demo01;import java.util.TimerTask;/*** 卖票 自己会写 3个售票员卖出30张票使用 juc.locks 包下的类操作 Lock 锁 + Lambda 表达式* 企业中禁止这样写,Coding:企业级开发!** 多线程编程的固定套路:* 1、高内聚,低耦合 (前提)* 2、线程 操作(调用对外暴露的方法) 资源类 (要点)*/public class SaleTicketTest1 {public static void main(String[] args) {// 资源类final SaleTicket saleTicket = new SaleTicket();new Thread(new Runnable() {public void run() {for (int i = 1; i < 40; i++) {saleTicket.saleTicket();}}}, "A").start();new Thread(new Runnable() {public void run() {for (int i = 1; i < 40; i++) {saleTicket.saleTicket();}}}, "B").start();new Thread(new Runnable() {public void run() {for (int i = 1; i < 40; i++) {saleTicket.saleTicket();}}}, "C").start();}}// 属性,和方法 高内聚class SaleTicket{ //资源类private int number = 30;// 卖票方法public synchronized void saleTicket(){if (number>0){System.out.println(Thread.currentThread().getName()+"卖出第"+(number--) +"还剩下:"+number+"张票");}}}
使用 juc.locks 包下的类操作 Lock 锁 + Lambda 表达式
package com.coding.demo01;import java.util.concurrent.locks.Lock;import java.util.concurrent.locks.ReentrantLock;/*** 卖票 自己会写 3个售票员卖出30张票* 企业中禁止这样写,Coding:企业级开发!* * 多线程编程的固定套路:* 1、高内聚,低耦合 (前提)* 2、线程 操作(调用对外暴露的方法) 资源类 (要点)*/public class SaleTicketTest2 {public static void main(String[] args) {// 并发:多线线程操作同一个资源类// 资源类SaleTicket2 saleTicket = new SaleTicket2();// lambda表达式、链式编程、流式计算!// lambda表达式,() -> {} 自动推断类型// IDEA 一定要设置 JDK 版本为 1.8 版本new Thread(() -> {for (int i = 1; i < 40; i++) saleTicket.saleTicket();}, "A").start();new Thread(() -> {for (int i = 1; i < 40; i++) saleTicket.saleTicket();}, "B").start()new Thread(() -> {for (int i = 1; i < 40; i++) saleTicket.saleTicket();}, "C").start();}}// 属性,和方法 高内聚class SaleTicket2 { //资源类private int number = 30;// 锁LOCKprivate Lock lock = new ReentrantLock(); // 可重入// 卖票方法public void saleTicket() {lock.lock(); // 加锁try {// 业务代码if (number > 0) {System.out.println(Thread.currentThread().getName() + "卖出第" +(number--) + "还剩下:" + number + "张票");}} catch (Exception e) {e.printStackTrace();} finally {lock.unlock(); // 解锁}}}
synchronized 和 lock 区别 (自动挡 手动挡)
synchronized 和 lock 区别
1、synchronized 关键字,Java内置的。lock 是一个Java 类
2、synchronized 无法判断是否获取锁、lock 可以判断是否获得锁
3、synchronized 锁会自动释放!lock 需要手动在 fifinally 释放锁,如果不释放锁,就会死锁
4、synchronized 线程1阻塞 线程2永久等待下去。lock可以 lock.tryLock(); // 尝试获取锁,如果尝试获取不到锁,可以结束等待
5、synchronized 可重入,不可中断,非公平的,Lock锁,可重入、可以判断、可以公平!
4、生产者和消费者(高频)
生产者和消费者 synchroinzed 版 (温馨提示:先看完视频,然后再进行去看代码,进行练习实操哦)线程间的通信、无法通信,调度线程
生产者和消费者 synchroinzed 版
package com.coding.demo02;/*** 题目:现在两个线程,操作一个初始值为0的变量* 一个线程 + 1, 一个线程 -1。判断什么时候+1,什么时候-1* 交替10 次** 方法论:** 多线程编程的固定套路:* 1、高内聚,低耦合 (前提)* 2、线程 操作(调用对外暴露的方法) 资源类 (要点)** 生产者消费者模型:判断、干活、通知*/public class A {public static void main(String[] args) {Data data = new Data();new Thread(()->{for (int i = 1; i <= 10; i++) {try {data.increment();} catch (Exception e) {e.printStackTrace();}}},"A").start();new Thread(()->{for (int i = 1; i <= 10; i++) {try {data.decrement();} catch (Exception e) {e.printStackTrace();}}},"B").start();}}// 资源类 属性,方法class Data{private int num = 0;// +1public synchronized void increment() throws Exception{//判断if (num!=0){this.wait();}// 干活num++;System.out.println(Thread.currentThread().getName()+"\t"+num);// 通知this.notifyAll();}// -1public synchronized void decrement() throws Exception{// 判断if (num==0){this.wait();}// 干活num--;System.out.println(Thread.currentThread().getName()+"\t"+num);// 通知this.notifyAll();}}
问题升级:防止虚假唤醒,4个线程,两个加,两个减
package com.coding.demo02;/*** 题目:现在两个线程,操作一个初始值为0的变量* 一个线程 + 1, 一个线程 -1。判断什么时候+1,什么时候-1* 交替10 次** 方法论:** 多线程编程的固定套路:* 1、高内聚,低耦合 (前提)* 2、线程 操作(调用对外暴露的方法) 资源类 (要点)** 生产者消费者模型:判断、干活、通知*/public class A {public static void main(String[] args) {Data data = new Data();new Thread(()->{for (int i = 1; i <= 10; i++) {try {data.increment();} catch (Exception e) {e.printStackTrace();}}},"A").start();new Thread(()->{for (int i = 1; i <= 10; i++) {try {data.decrement();} catch (Exception e) {e.printStackTrace();}}},"B").start();new Thread(()->{for (int i = 1; i <= 10; i++) {try {data.increment();} catch (Exception e) {e.printStackTrace();}}},"C").start();new Thread(()->{for (int i = 1; i <= 10; i++) {try {data.decrement();} catch (Exception e) {e.printStackTrace();}}},"D").start();}}// 资源类 属性,方法class Data{private int num = 0;// +1public synchronized void increment() throws Exception{//判断 if 只判断了一次, 0 1 0 1while (num!=0){this.wait();}// 干活num++;System.out.println(Thread.currentThread().getName()+"\t"+num);// 通知this.notifyAll();}// -1public synchronized void decrement() throws Exception{// 判断while (num==0){this.wait(); //0}// 干活num--;System.out.println(Thread.currentThread().getName()+"\t"+num);// 通知this.notifyAll();}}
传统的,JUC!
新版生产者和消费者写法
任何一个新技术的出现,一定不仅仅是换了个马甲
手写生产者消费者问题:100 加分项目!
package com.coding.demo02;import sun.awt.SunHints;import java.util.concurrent.locks.Condition;import java.util.concurrent.locks.Lock;import java.util.concurrent.locks.ReentrantLock;// lock版生产者消费者public class B {public static void main(String[] args) {// 新版Data2 data = new Data2();new Thread(()->{for (int i = 1; i <= 10; i++) {try {data.increment();} catch (Exception e) {e.printStackTrace();}}},"A").start();new Thread(()->{for (int i = 1; i <= 10; i++) {try {data.decrement();} catch (Exception e) {e.printStackTrace();}}},"B").start();new Thread(()->{for (int i = 1; i <= 10; i++) {try {data.increment();} catch (Exception e) {e.printStackTrace();}}},"C").start();new Thread(()->{for (int i = 1; i <= 10; i++) {try {data.decrement();} catch (Exception e) {e.printStackTrace();}}},"D").start();}}// 资源类 属性,方法class Data2{private int num = 0;// 定义锁Lock lock = new ReentrantLock();private Condition condition = lock.newCondition();// +1public void increment() throws Exception{// 加锁lock.lock();try {//判断while (num!=0){condition.await(); //等待}// 干活num++;System.out.println(Thread.currentThread().getName()+"\t"+num);// 通知condition.signalAll();} catch (InterruptedException e) {e.printStackTrace();} finally {// 解锁lock.unlock();}}// -1public void decrement() throws Exception{// 加锁lock.lock();try {// 判断while (num==0){condition.await(); //等待}// 干活num--;System.out.println(Thread.currentThread().getName()+"\t"+num);// 通知condition.signalAll();} catch (InterruptedException e) {e.printStackTrace();} finally {// 解锁lock.unlock();}}}
如何精确通知访问!
精确通知顺序访问 Condition
package com.coding.demo02;import java.util.concurrent.locks.Condition;import java.util.concurrent.locks.Lock;import java.util.concurrent.locks.ReentrantLock;/*** 多个线程启动 A -- B -- C* 三个线程依次打印* A 5次* B 10次* C 15次* 依次循环** 精确通知线程消费*/public class C {public static void main(String[] args) {Data3 data = new Data3();// 线程操作资源类new Thread(()->{for (int i = 1; i <= 10; i++) {data.print5();}},"A").start();new Thread(()->{for (int i = 1; i <= 10; i++) {data.print10();}},"B").start();new Thread(()->{for (int i = 1; i <= 10; i++) {data.print15();}},"C").start();}}// 资源类 属性,方法class Data3{private int num = 1; // A1 B2 C3// 定义锁Lock lock = new ReentrantLock();private Condition condition1 = lock.newCondition(); //3个判断,交替执行 A--B--C--Aprivate Condition condition2 = lock.newCondition(); //3个判断,交替执行 A--B--C--Aprivate Condition condition3 = lock.newCondition(); //3个判断,交替执行 A--B--C--A// 3个方法、作业,合3为1// +1public void print5(){// 加锁lock.lock();try {//判断while (num!=1){condition1.await(); //等待}// 干活for (int i = 1; i <=5 ; i++) {System.out.println(Thread.currentThread().getName()+"\t"+i);}// 第一个线程通知第二个线程,第二个线程通知第三个.... 计数器num=2;// 通知第二个线程干活,指定谁干活condition2.signal();} catch (InterruptedException e) {e.printStackTrace();} finally {// 解锁lock.unlock();}}public void print10() {// 加锁lock.lock();try {//判断while (num!=2){condition2.await(); //等待}// 干活for (int i = 1; i <=10 ; i++) {System.out.println(Thread.currentThread().getName()+"\t"+i);}// 第一个线程通知第二个线程,第二个线程通知第三个.... 计数器num=3;// 通知第二个线程干活,指定谁干活condition3.signal();} catch (InterruptedException e) {e.printStackTrace();} finally {// 解锁lock.unlock();}}public void print15() {// 加锁lock.lock();try {//判断while (num!=3){condition3.await(); //等待}// 干活 = 业务代码for (int i = 1; i <=15 ; i++) {System.out.println(Thread.currentThread().getName()+"\t"+i);}num=1;condition1.signal();} catch (InterruptedException e) {e.printStackTrace();} finally {// 解锁lock.unlock();}}}
大家懂锁的吗?锁的谁!
下节课预告:会为大家分享JUC并发编程系列课8锁的现象(深入理解锁)
,欢迎大家关注我们哦