package com.hkx.pc;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
/**
* @program: juc
* @description: 09-Condition实现精准通知唤醒
* @author: Casey Hu
* @create: 2022-08-14 19:51
**/
/**
* A执行完,调用B。B执行完,调用C。C执行完,调用A。
*/
public class C {
public static void main(String[] args) {
Data3 data3=new Data3();
new Thread(()->{
for (int i=0;i<10;i++){
data3.printA();
}
},"A").start();
new Thread(()->{
for (int i=0;i<10;i++){
data3.printB();
}
},"B").start();
new Thread(()->{
for (int i=0;i<10;i++){
data3.printC();
}
},"C").start();
}
}
class Data3{
private Lock lock=new ReentrantLock();
private Condition condition1 = lock.newCondition();
private Condition condition2 = lock.newCondition();
private Condition condition3 = lock.newCondition();
private int num=1;
public void printA(){
lock.lock();
try {
//业务——>判断——>执行——>通知
while(1!=num){
condition1.await();
}
System.out.println(Thread.currentThread().getName()+"=>AAAAA");
num=2;
//唤醒指定的人 B
condition2.signal();
} catch (Exception e) {
throw new RuntimeException(e);
} finally {
lock.unlock();
}
}
public void printB(){
lock.lock();
try {
//业务——>判断——>执行——>通知
while (2!=num){
condition2.await();
}
System.out.println(Thread.currentThread().getName()+"=>BBBBB");
num=3;
//唤醒指定的人 C
condition3.signal();
} catch (Exception e) {
throw new RuntimeException(e);
} finally {
lock.unlock();
}
}
public void printC(){
lock.lock();
try {
//业务——>判断——>执行——>通知
while(num!=3){
condition3.await();
}
System.out.println(Thread.currentThread().getName()+"=>CCCCC");
num=1;
//唤醒指定的人 A
condition1.signal();
} catch (Exception e) {
throw new RuntimeException(e);
} finally {
lock.unlock();
}
}
}
上面的代码主要设置了多个监视器,随时唤醒指定的线程。
购物场景:在下单完成之后,调用支付操作,在支付完成之后调用交易完成页面,在交易完成之后调用物流操作
5、8锁现象
如何判断锁是谁,永远知道什么是锁,锁到底锁的是谁!
深刻理解锁是什么
package com.hkx.lock8;
/**
* @program: juc
* @description:
* @author: Casey Hu
* @create: 2022-08-21 20:14
**/
import java.util.concurrent.TimeUnit;
/***
*
*8锁,就是关于锁的8个问题
* 1、在标准情况下,两个线程是先打印哪个呢? 1发短信 2打电话
* 2、发短信的方法延迟四秒,两个线程是先打印哪个呢? 1发短信 2打电话
*/
public class Test1 {
public static void main(String[] args) {
Phone phone=new Phone();
new Thread(()->{
phone.sendSms();
},"A").start();
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
new Thread(()->{
phone.call();
},"B").start();
}
}
class Phone{
//被synchronized修饰的方法,锁的是方法的调用者
//两个方法用的是同一把锁phone的锁,哪个方法先拿到就先执行哪个
public synchronized void sendSms(){
try {
TimeUnit.SECONDS.sleep(4);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
System.out.println("发短信");
}
public synchronized void call(){
System.out.println("打电话");
}
}
package com.hkx.lock8;
import java.util.concurrent.TimeUnit;
/**
* @program: juc
* @description:
* @author: Casey Hu
* @create: 2022-08-21 21:15
**/
/**
* 3、曾加了一个普通方法,是先执行发短信还是执行hello? hello 发短信 1秒钟输出hello,四秒中说出发短信
* 4、两个对象,都执行同步方法 是先执行哪个?
*/
public class Test2 {
public static void main(String[] args) {
//两个对象,两个调用者,两把锁
Phone2 phone1=new Phone2();
Phone2 phone2=new Phone2();
new Thread(()->{
phone1.sendSms();
},"A").start();
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
new Thread(()->{
phone2.call();
},"B").start();
}
}
class Phone2{
//被synchronized修饰的方法,锁的是方法的调用者
//两个方法用的是同一把锁phone的锁,哪个方法先拿到就先执行哪个
public synchronized void sendSms(){
try {
TimeUnit.SECONDS.sleep(4);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
System.out.println("发短信");
}
public synchronized void call(){
System.out.println("打电话");
}
//没有锁,不受锁的影响
public void hello(){
System.out.println("hello");
}
}
package com.hkx.lock8;
import java.util.concurrent.TimeUnit;
/**
* @program: juc
* @description:
* @author: Casey Hu
* @create: 2022-08-21 21:32
**/
/***
* 5.增加两个静态同步方法,只有一个对象,是先打印哪个? 发短信 打电话
* 6、两个对象,增加两个静态同步方法,是先打印哪个? 发短信 打电话
*/
public class Test3 {
public static void main(String[] args) {
//两个对象,锁的模板只有一个,
Phone3 phone1 =new Phone3();
Phone3 phone2 =new Phone3();
new Thread(()->{
phone1.sendSms();
},"A").start();
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
new Thread(()->{
phone2.call();
},"B").start();
}
}
//5、Phone3 只有唯一 的Class对象,static锁的是class
//6、两个对象,增加两个同步方法,是先打印,还是先发短信,打电话。
class Phone3{
//被synchronized修饰的方法,锁的是方法的调用者
//static 静态方法,在类一加载就有了! Class 模板
public static synchronized void sendSms(){
try {
TimeUnit.SECONDS.sleep(4);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
System.out.println("发短信");
}
public static synchronized void call(){
System.out.println("打电话");
}
}
package com.hkx.lock8;
import java.util.concurrent.TimeUnit;
/**
* @program: juc
* @description:
* @author: Casey Hu
* @create: 2022-08-21 21:51
**/
/**
* 7、一个对象,一个静态同步方法,一个普通同步方法,是先打印哪个? 打电话 发短信
* 7、两个对象,一个静态同步方法,一个普通同步方法,是先打印哪个? 打电话 发短信
*/
public class Test4 {
public static void main(String[] args) {
//两个对象,锁的模板只有一个,
Phone4 phone1 =new Phone4();
Phone4 phone2 =new Phone4();
new Thread(()->{
phone1.sendSms();
},"A").start();
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
new Thread(()->{
phone2.call();
},"B").start();
}
}
//5、Phone3 只有唯一 的Class对象,static锁的是class
//6、两个对象,增加两个同步方法,是先打印,还是先发短信,打电话。
class Phone4{
//static 静态方法,在类一加载就有了!锁的是Class 模板
public static synchronized void sendSms(){
try {
TimeUnit.SECONDS.sleep(4);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
System.out.println("发短信");
}
//被synchronized修饰的方法,锁的是方法的调用者
public synchronized void call(){
System.out.println("打电话");
}
}
小结
到底锁,锁的是啥? new出来的,static修饰的
new this 具体的一个
static Class 唯一的一个模板
6、集合类不安全
List
package com.hkx.unsafe;
import java.util.*;
import java.util.concurrent.CopyOnWriteArrayList;
/**
* @program: juc
* @description: 集合类不安全_List
* @author: Casey Hu
* @create: 2022-09-18 17:39
**/
// java.util.ConcurrentModificationException 并发修改异常
public class ListTest {
public static void main(String[] args) {
//并发下 ArrayList 是不安全的
/**
* 解决方案:
* 1.List<String> list = new Vector<>();
* 2.由于ArrayList 不安全,我们选择使用工具类的转化,让ArrayList 变得安全
* List<String> list = Collections.synchronizedList(new ArrayList<>());
* 3.List<String> list =new CopyOnWriteArrayList<String>();
* CopyOnWrite 写入时候复制 COW 是计算机程序设计领域的一直优化策略
*多个线程调用的时候,比如唯一的list 在读取的时候是固定的,写入的时候会出现,覆盖的情况
* 在写的入的时候避免覆盖造成数据问题,造成数据问题
* 注意:CopyOnWriteArrayList 比 Vector 强在哪?
* 就是在 CopyOnWriteArrayList 没有 synchronized 修饰采用的 是复制一份在重新赋值的逻辑
* Vector 里有synchronized 修饰 效率会很低
*/
// List<String> list = new Vector<>();
// List<String> list = Collections.synchronizedList(new ArrayList<>());
List<String> list =new CopyOnWriteArrayList<String>();
for (int i=1;i<=10;i++){
new Thread(()->{
list.add(UUID.randomUUID().toString().substring(0,5));
System.out.println(list);
},String.valueOf(i)).start();
}
}
}