8锁现象
如何判断锁的是谁!锁到底锁的是谁?
锁会锁住:对象、Class
深刻理解我们的锁
问题1:多个线程使用同一把锁-顺序执行
package com.whf.juc.lock8;
/**
* @ClassName Test1
* @Description Test1
* @Author 德鲁大叔
* @Date 2021/1/14 16:17
* @Version 1.0
*/
import java.util.concurrent.TimeUnit;
/**
* 8锁就是关于锁的8个问题
* 1.标准情况下,两个线程先打印 发短信还是打电话
*/
public class Test1 {
public static void main(String[] args) {
Phone phone = new Phone();
//锁的存在
new Thread(()->{
phone.sendSms();
}, "A").start();
//捕获
try {
TimeUnit.SECONDS.sleep(1);//休息1s
} catch (InterruptedException e) {
e.printStackTrace();
}
new Thread(()->{
phone.call();
}, "B").start();
}
}
class Phone {
//synchronized的对象是方法的调用者
//两个对象用的同一个锁,谁先拿到谁执行
public synchronized void sendSms() {
System.out.println("发短信");
}
public synchronized void call() {
System.out.println("打电话");
}
}
打电话
发短信
Process finished with exit code 0
问题2:多个线程使用同一把锁,其中某个线程里面还有阻塞-顺序先执行
package com.whf.juc.lock8;
/**
* @ClassName Test1
* @Description Test1
* @Author 德鲁大叔
* @Date 2021/1/14 16:17
* @Version 1.0
*/
import java.util.concurrent.TimeUnit;
/**
* 8锁就是关于锁的8个问题
* 1.标准情况下,两个线程先打印 发短信还是打电话
*/
public class Test1 {
public static void main(String[] args) {
Phone phone = new Phone();
//锁的存在
new Thread(()->{
phone.sendSms();
}, "A").start();
//捕获
try {
TimeUnit.SECONDS.sleep(1);//休息1s
} catch (InterruptedException e) {
e.printStackTrace();
}
new Thread(()->{
phone.call();
}, "B").start();
}
}
class Phone {
//synchronized的对象是方法的调用者
//两个对象用的同一个锁,谁先拿到谁执行
public synchronized void sendSms() {
try {
TimeUnit.SECONDS.sleep(4);//休息4s
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("发短信");
}
public synchronized void call() {
System.out.println("打电话");
}
}
打电话
发短信
Process finished with exit code 0
问题三:多个线程有锁与没锁-随机执行
package com.interview.concurrent.lock.locakType;
import java.util.concurrent.TimeUnit;
/**
* @author yangxj
* @description 描述
* @date 2020/2/22 15:57
*/
public class MultiThreadHaveLockAndNot03 {
public static void main(String[] args){
Mobile3 mobile = new Mobile3();
// 两个线程使用的是同一个对象。两个线程是一把锁!先调用的先执行!
new Thread(()->mobile.sendEmail(),"A").start();
// 干扰
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
new Thread(()->mobile.sendMS(),"B").start();
new Thread(()->mobile.getWeixinMs(),"C").start();
}
}
// 手机,发短信,发邮件
class Mobile3 {
// 被 synchronized 修饰的方法、锁的对象是方法的调用者、
public synchronized void sendEmail() {
//多个线程使用一把锁,这里设置一个干扰
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("sendEmail");
}
public synchronized void sendMS() {
System.out.println("sendMS");
}
//接收微信,没有锁
public void getWeixinMs() {
System.out.println("getWeixinMs");
}
}
问题四:多个线程使用多把锁-随机执行
1、被 synchronized 修饰的方法,锁的对象是方法的调用者;
2、调用者不同,它们之间用的不是同一个锁,相互之间没有关系。
package com.whf.juc.lock8;
import java.util.concurrent.TimeUnit;
/**
* @ClassName Test2
* @Description Test2
* @Author 德鲁大叔
* @Date 2021/1/14 16:43
* @Version 1.0
*/
/**
* 3.增加一个普通方法 先发短信还是先hello
* 4.两个对象两个同步方法 先发短信还是先打电话
*/
public class Test2 {
public static void main(String[] args) {
//两个对象 两个调用者 两把锁
Phone2 phone = new Phone2();
Phone2 phone2 = new Phone2();
//锁的存在
new Thread(()->{
phone.sendSms();
}, "A").start();
//捕获
try {
TimeUnit.SECONDS.sleep(1);//休息1s
} catch (InterruptedException e) {
e.printStackTrace();
}
new Thread(()->{
phone2.call();
}, "B").start();
}
}
class Phone2 {
//synchronized的对象是方法的调用者
//两个对象用的同一个锁,谁先拿到谁执行
public synchronized void sendSms() {
try {
TimeUnit.SECONDS.sleep(4);//休息4s
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("发短信");
}
public synchronized void call() {
System.out.println("打电话");
}
//没有锁 没有锁的影响
public void hello() {
System.out.println("hello");
}
}
问题五:Class锁:多个线程使用一个对象-顺序执行
被 synchronized 和 static 同时修饰的方法,锁的对象是类的 class 对象,是唯一的一把锁。线程之间是顺序执行。
锁Class和锁对象的区别:
1、Class 锁 ,类模版,只有一个;
2、对象锁 , 通过类模板可以new 多个对象。
如果全部都锁了Class,那么这个类下的所有对象都具有同一把锁。
package com.whf.juc.lock8;
import java.util.concurrent.TimeUnit;
/**
* @ClassName Test3
* @Description Test3
* @Author 德鲁大叔
* @Date 2021/1/15 15:45
* @Version 1.0
*/
/**
* 5.增加两个静态同步方法只有一个对象 先发短信还是先打电话
* 6.两个对象 增加两个静态同步方法只有一个对象 先发短信还是先打电话
*/
public class Test3 {
public static void main(String[] args) {
//两个对象的class类模板只有一个 static锁的是class
Phone3 phone = new Phone3();
// Phone3 phone2 = new Phone3();
//锁的存在
new Thread(()->{
phone.sendSms();
}, "A").start();
//捕获
try {
TimeUnit.SECONDS.sleep(1);//休息1s
} catch (InterruptedException e) {
e.printStackTrace();
}
new Thread(()->{
phone.call();
}, "B").start();
}
}
//Phone3是唯一的class对象
class Phone3 {
//synchronized的对象是方法的调用者
//两个对象用的同一个锁,谁先拿到谁执行
//static静态方法 类一加载就有了 class模板 锁的是class
public static synchronized void sendSms() {
try {
TimeUnit.SECONDS.sleep(4);//休息4s
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("发短信");
}
public static synchronized void call() {
System.out.println("打电话");
}
}
问题六:Class锁:多个线程使用多个对象-顺序执行
package com.whf.juc.lock8;
import java.util.concurrent.TimeUnit;
/**
* @ClassName Test3
* @Description Test3
* @Author 德鲁大叔
* @Date 2021/1/15 15:45
* @Version 1.0
*/
/**
* 5.增加两个静态同步方法只有一个对象 先发短信还是先打电话
* 6.两个对象 增加两个静态同步方法只有一个对象 先发短信还是先打电话
*/
public class Test3 {
public static void main(String[] args) {
//两个对象的class类模板只有一个 static锁的是class
Phone3 phone = new Phone3();
Phone3 phone2 = new Phone3();
//锁的存在
new Thread(()->{
phone.sendSms();
}, "A").start();
//捕获
try {
TimeUnit.SECONDS.sleep(1);//休息1s
} catch (InterruptedException e) {
e.printStackTrace();
}
new Thread(()->{
phone2.call();
}, "B").start();
}
}
//Phone3是唯一的class对象
class Phone3 {
//synchronized的对象是方法的调用者
//两个对象用的同一个锁,谁先拿到谁执行
//static静态方法 类一加载就有了 class模板 锁的是class
public static synchronized void sendSms() {
try {
TimeUnit.SECONDS.sleep(4);//休息4s
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("发短信");
}
public static synchronized void call() {
System.out.println("打电话");
}
}
问题七:Class锁与对象锁:多个线程使用一个对象-随机执行
被 synchronized和static修饰的方法,锁的对象是类的class对象!唯一的同一把锁;
只被synchronized修饰的方法,是普通锁(如对象锁),不是Class锁,所以进程之间执行顺序互不干扰。
package com.whf.juc.lock8;
import java.util.concurrent.TimeUnit;
/**
* @ClassName Test4
* @Description Test4
* @Author 德鲁大叔
* @Date 2021/1/15 15:53
* @Version 1.0
*/
/**
* 7.一个普通方法一个静态方法 先发短信还是先打电话
* 8.两个对象 一个普通方法一个静态方法 先发短信还是先打电话
*/
public class Test4 {
public static void main(String[] args) {
//两个对象的class类模板只有一个 static锁的是class
Phone4 phone = new Phone4();
Phone4 phone2 = new Phone4();
//锁的存在
new Thread(()->{
phone.sendSms();
}, "A").start();
//捕获
try {
TimeUnit.SECONDS.sleep(1);//休息1s
} catch (InterruptedException e) {
e.printStackTrace();
}
new Thread(()->{
phone.call();
}, "B").start();
}
}
//Phone3是唯一的class对象
class Phone4 {
//synchronized的对象是方法的调用者
//两个对象用的同一个锁,谁先拿到谁执行
//static静态方法 类一加载就有了 class模板 锁的是class类模板
public static synchronized void sendSms() {
try {
TimeUnit.SECONDS.sleep(4);//休息4s
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("发短信");
}
//普通同步方法
//锁的是调用者
public synchronized void call() {
System.out.println("打电话");
}
}
问题八:Class锁与对象锁:多个线程使用多个对象-随机执行
被 synchronized和static修饰的方法,锁的对象是类的class对象!唯一的同一把锁;
只被synchronized修饰的方法,是普通锁(如对象锁),不是Class锁,所以进程之间执行顺序互不干扰。
package com.whf.juc.lock8;
import java.util.concurrent.TimeUnit;
/**
* @ClassName Test4
* @Description Test4
* @Author 德鲁大叔
* @Date 2021/1/15 15:53
* @Version 1.0
*/
/**
* 7.一个普通方法一个静态方法 先发短信还是先打电话
* 8.两个对象 一个普通方法一个静态方法 先发短信还是先打电话
*/
public class Test4 {
public static void main(String[] args) {
//两个对象的class类模板只有一个 static锁的是class
Phone4 phone = new Phone4();
Phone4 phone2 = new Phone4();
//锁的存在
new Thread(()->{
phone.sendSms();
}, "A").start();
//捕获
try {
TimeUnit.SECONDS.sleep(1);//休息1s
} catch (InterruptedException e) {
e.printStackTrace();
}
new Thread(()->{
phone2.call();
}, "B").start();
}
}
//Phone3是唯一的class对象
class Phone4 {
//synchronized的对象是方法的调用者
//两个对象用的同一个锁,谁先拿到谁执行
//static静态方法 类一加载就有了 class模板 锁的是class类模板
public static synchronized void sendSms() {
try {
TimeUnit.SECONDS.sleep(4);//休息4s
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("发短信");
}
//普通同步方法
//锁的是调用者
public synchronized void call() {
System.out.println("打电话");
}
}
new this 本身的这个对象,调用者
static class 类模板,保证唯一!
集合类问题
List不安全
package com.whf.juc.unsafe;
import java.util.*;
import java.util.concurrent.CopyOnWriteArrayList;
/**
* @ClassName ListTest
* @Description ListTest
* @Author 德鲁大叔
* @Date 2021/1/15 16:19
* @Version 1.0
*/
//ConcurrentModificationException
public class ListTest {
public static void main(String[] args) {
/**
* ArrayList多线程不安全
* 1.List<String> lists = new Vector<>();
* 2.List<String> lists = Collections.synchronizedList(new ArrayList<>());
* List<String> lists = new CopyOnWriteArrayList<>();***
*/
List<String> lists = new ArrayList<>();
//CopyOnWrite写入时复制 COW 计算机的一种优化策略
//多个线程调用时 list 读取固定 写入的时候 复制出来 再覆盖
//在写入的时候避免覆盖 造成数据问题
//读写分离
//CopyOnWriteArrayList 比 Vector牛逼在哪里
//CopyOnWriteArrayList读操作不需要同步 不需要synchronized
//Vector读写都需要synchronized
//List<String> lists = new CopyOnWriteArrayList<>();
for (int i = 0; i < 10; i++) {
new Thread(() -> {
lists.add(UUID.randomUUID().toString().substring(0, 5));
System.out.println(lists);
}, String.valueOf(i)).start();
}
}
}
使用一下三种解决方案
/**
* ArrayList多线程不安全
* 1.List<String> lists = new Vector<>();
* 2.List<String> lists = Collections.synchronizedList(new ArrayList<>());
* List<String> lists = new CopyOnWriteArrayList<>();***
*/
//CopyOnWrite写入时复制 COW 计算机的一种优化策略
//多个线程调用时 list 读取固定 写入的时候 复制出来 再覆盖
//在写入的时候避免覆盖 造成数据问题
//读写分离
//CopyOnWriteArrayList 比 Vector牛逼在哪里
//CopyOnWriteArrayList读操作不需要同步 不需要synchronized
//Vector读写都需要synchronized
Set不安全
/**
* 解决方法
* 1.Set<String> set = Collections.synchronizedSet(new HashSet<>());
* 2.Set<String> set = new CopyOnWriteArraySet<>();
*/
package com.whf.juc.unsafe;
import java.util.Collections;
import java.util.HashSet;
import java.util.Set;
import java.util.UUID;
import java.util.concurrent.CopyOnWriteArraySet;
/**
* @ClassName SetTest
* @Description SetTest
* @Author 德鲁大叔
* @Date 2021/1/15 17:18
* @Version 1.0
*/
//ConcurrentModificationException
public class SetTest {
public static void main(String[] args) {
//Set<String> set = new HashSet<>();
/**
* 解决方法
* 1.Set<String> set = Collections.synchronizedSet(new HashSet<>());
* 2.Set<String> set = new CopyOnWriteArraySet<>();
*/
Set<String> set = new CopyOnWriteArraySet<>();
for (int i = 0; i < 30; i++) {
new Thread(() -> {
set.add(UUID.randomUUID().toString().substring(0, 5));
System.out.println(set);
}, String.valueOf(i)).start();
}
}
}
hashSet 底层是什么?
public HashSet() {
map = new HashMap<>();
}
// add set 本质就是 map key是无法重复的!
public boolean add(E e) {
return map.put(e, PRESENT)==null;
}
private static final Object PRESENT = new Object(); // 不变得值!
Map 不安全
package com.whf.juc.unsafe;
import java.util.Collections;
import java.util.HashSet;
import java.util.Set;
import java.util.UUID;
import java.util.concurrent.CopyOnWriteArraySet;
/**
* @ClassName SetTest
* @Description SetTest
* @Author 德鲁大叔
* @Date 2021/1/15 17:18
* @Version 1.0
*/
//ConcurrentModificationException
public class SetTest {
public static void main(String[] args) {
//Set<String> set = new HashSet<>();
/**
* 解决方法
* 1.Set<String> set = Collections.synchronizedSet(new HashSet<>());
* 2.Set<String> set = new CopyOnWriteArraySet<>();
*/
Set<String> set = new CopyOnWriteArraySet<>();
for (int i = 0; i < 30; i++) {
new Thread(() -> {
set.add(UUID.randomUUID().toString().substring(0, 5));
System.out.println(set);
}, String.valueOf(i)).start();
}
}
}