Thread safety of an ArrayList collection
Introducing thread unsafety issues
package new_course.chp3.list_demo;
import java.util.ArrayList;
import java.util.UUID;
/**
* @author Created by Lin Weihong
* @date on 2022/6/1 21:33
* List集合线程不安全
*/
public class ErrorList {
public static void main(String[] args) {
//创建ArrayList集合
List<String> list = new ArrayList<>();
for (int i = 0; i < 10; i++) {
new Thread(() -> {
//往集合添加内容
list.add(UUID.randomUUID().toString().substring(0, 8));
//从集合取出内容
System.out.println(list);
}, String.valueOf(i)).start();
}
}
}
//结果:
java.util.ConcurrentModificationException
程序会报错,修改异常
Solution Vector Collections collection
package new_course.chp3.list_demo;
import java.util.*;
/**
* @author Created by Lin Weihong
* @date on 2022/6/1 21:33
* List集合线程不安全
*/
public class ErrorList {
public static void main(String[] args) {
//Vector解决
// List<String> list = new Vector<>();
//Collections解决
List<String> list = Collections.synchronizedList(new ArrayList<>());
for (int i = 0; i < 10; i++) {
new Thread(() -> {
//往集合添加内容
list.add(UUID.randomUUID().toString().substring(0, 8));
//从集合取出内容
System.out.println(list);
}, String.valueOf(i)).start();
}
}
}
Workaround CopyOnWriteArrayList
package new_course.chp3.list_demo;
import java.util.List;
import java.util.UUID;
import java.util.concurrent.CopyOnWriteArrayList;
/**
* @author Created by Lin Weihong
* @date on 2022/6/1 22:38
*/
public class Solution2 {
public static void main(String[] args) {
List<String> list = new CopyOnWriteArrayList<>();
for (int i = 0; i < 10; i++) {
new Thread(() -> {
//存入集合
list.add(UUID.randomUUID().toString().substring(0,8));
//从集合当中取出
System.out.println(list);
},String.valueOf(i)).start();
}
}
}
CopyOnWriteArrayList principle
- Supports concurrent read operations
- When writing, first copy the current container, and then perform the write operation on the new copy
- After the end, point the reference of the original container to the new container
//CopyOnWriteArrayList 的add 源码
public boolean add(E e) {
final ReentrantLock lock = this.lock;
lock.lock();
try {
Object[] elements = getArray(); //原始数组
int len = elements.length;
Object[] newElements = Arrays.copyOf(elements, len + 1);//复制得到的新数组
newElements[len] = e;
setArray(newElements);//调用下面的setArray方法
return true;
} finally {
lock.unlock();
}
}
final void setArray(Object[] a) {
array = a;//将原本的引用指向新的数组
}
Thread safety of two HashSet collections
Introducing thread unsafety issues
package new_course.chp3.hashset_demo;
import java.util.HashSet;
import java.util.Set;
import java.util.UUID;
/**
* @author Created by Lin Weihong
* @date on 2022/6/2 0:21
* 演示HashSet线程不安全
*/
public class ErrorHashSet {
public static void main(String[] args) {
Set<String> set = new HashSet<>();
for (int i = 0; i < 30; i++) {
new Thread(() -> {
//放入set集合
set.add(UUID.randomUUID().toString().substring(0,8));
//从set集合取出
System.out.println(set);
},String.valueOf(i)).start();
}
}
}
//程序报错
Workaround CopyOnWriteArraySet
/**
* @author Created by Lin Weihong
* @date on 2022/6/2 0:21
* 演示HashSet线程不安全
*/
public class Solution1{
public static void main(String[] args) {
Set<String> set = new CopyOnWriteArraySet<>();
for (int i = 0; i < 30; i++) {
new Thread(() -> {
//放入set集合
set.add(UUID.randomUUID().toString().substring(0,8));
//从set集合取出
System.out.println(set);
},String.valueOf(i)).start();
}
}
}
Thread safety of three HashMap collections
Introducing thread unsafety issues
package new_course.chp3.hashmap_demo;
import java.util.Map;
import java.util.UUID;
import java.util.HashMap;
/**
* @author Created by Lin Weihong
* @date on 2022/6/2 0:27
* 演示HashMap线程不安全问题
*/
public class ErrorHashMap {
public static void main(String[] args) {
Map<String, String> map = new HashMap<>();
for (int i = 0; i < 10; i++) {
String key = String.valueOf(i);
new Thread(() -> {
//放入集合
map.put(String.valueOf(key),UUID.randomUUID().toString().substring(0,8));
//取出集合
System.out.println(map);
},String.valueOf(i)).start();
}
}
}
//程序报错
Solution ConcurrentHashMap
package new_course.chp3.hashmap_demo;
import java.util.HashMap;
import java.util.Map;
import java.util.UUID;
import java.util.concurrent.ConcurrentHashMap;
/**
* @author Created by Lin Weihong
* @date on 2022/6/2 0:36
*/
public class Solution1 {
public static void main(String[] args) {
Map<String, String> map = new ConcurrentHashMap<>();
for (int i = 0; i < 50; i++) {
String key = String.valueOf(i);
new Thread(() -> {
//放入集合
map.put(String.valueOf(key), UUID.randomUUID().toString().substring(0, 8));
//取出集合
System.out.println(map);
}, String.valueOf(i)).start();
}
}
}
Four multithreaded locks
eight-lock phenomenon
package new_course.chp3;
import java.util.concurrent.TimeUnit;
/**
* @author Created by Lin Weihong
* @date on 2022/6/2 0:47
*/
class Phone {
public synchronized void sendSMS() {
//停留4秒
try {
TimeUnit.SECONDS.sleep(4);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("------sendSMS");
}
public static synchronized void sendSMS1() {
//停留4秒
try {
TimeUnit.SECONDS.sleep(4);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("------sendSMS1");
}
public synchronized void sendEmail() {
System.out.println("------sendEmail");
}
public static synchronized void sendEmail1() {
System.out.println("------sendEmail1");
}
public void getHello() {
System.out.println("------getHello");
}
}
public class Lock8 {
public static void main(String[] args) throws InterruptedException {
Phone phone1 = new Phone();
Phone phone2 = new Phone();
new Thread(() -> {
// phone1.sendSMS();
phone1.sendSMS1();
}, "线程1").start();
Thread.sleep(100);
new Thread(() -> {
// phone1.getHello();
phone2.sendEmail();
// phone1.sendEmail();
// phone2.sendEmail1();
}, "线程2").start();
}
}
/**
* @Description 8锁
* <p>
* 1、标准访问,先打印短信还是邮件
* ------sendSMS
* ------sendEmail
* <p>
* 2、停4秒在短信方法内,先打印短信还是邮件
* ------sendSMS
* ------sendEmail
* -------------------------synchronized锁的是当前对象this,所以上面两个都是一样的结果----------------------
* <p>
* 3、新增普通的hello方法,先打印短信(4s)还是hello
* ------getHello
* ------sendSMS
* -------------------------sendSMS被锁住了,但是普通方法没有被锁----------------------
* <p>
* 4、现在有两部手机,先打印短信(4s)还是邮件
* ------sendEmail
* ------sendSMS
* -------------------------synchronized锁的是当前对象this,两部手机分别为两个不同对象,所以被锁的是phone1,但是phone2没有被锁----------------------
* 5、两个静态同步方法,1部手机,先打印短信还是邮件
* ------sendSMS1
* ------sendEmail1
*
* 6、两件静态同步方法,2部手机,先打印短信还是邮件
* ------sendSMS1
* ------sendEmail1
* -------------------------以上两个方法,static+synchronized,锁的是类对象Class--------------
* 7、1个静态同步方法,1个普通同步方法,1部手机,先打印短信还是邮件
* ------sendEmail
* ------sendSMS1
* <p>
* 8、1个静态同步方法,1个普通同步方法,2部手机,先打印短信还是邮件
* ------sendEmail
* ------sendSMS1
*
*/
Fair locks and unfair locks
For the previous ticket selling problem, suppose that there are four threads selling tickets (AA, BB, CC, DD) together at this time. If it is an unfair lock (default), it may happen that one thread sells all the tickets, while other threads do not. The situation of ticket sales. The fair lock means that every resource can have the opportunity to sell tickets together, reducing the occurrence ofDrought, drought, flood, floodscene.
How to declare fair locks and unfair locks
//公平锁
private final ReentrantLock lock = new ReentrantLock(true);
//非公平锁
private final ReentrantLock lock = new ReentrantLock(true);
Unfair lock: high efficiency, thread starvation
Fair lock: low efficiency, everyone has a share
Reentrant lock (recursive lock)
re-entrant lock
synchronized (implicit lock)
package new_course.chp3;
/**
* @author Created by Lin Weihong
* @date on 2022/6/2 11:21
* 可重入锁
*/
public class SyncLockDemo {
public synchronized void test() {
test(); //Exception in thread "main" java.lang.StackOverflowError,如果不是可重入锁,就不会栈溢出,因为被锁住了
}
public static void main(String[] args) {
SyncLockDemo syncLockDemo = new SyncLockDemo();
syncLockDemo.test();
// Object o = new Object();
// new Thread(() -> {
// synchronized (o) {
// System.out.println(Thread.currentThread().getName() + "外层");
// synchronized (o) {
// System.out.println(Thread.currentThread().getName() + "中层");
// synchronized (o) {
// System.out.println(Thread.currentThread().getName() + "内层");
// synchronized (o) {
// System.out.println(Thread.currentThread().getName() + "底层");
// }
// }
// }
// }
// }, "aa").start();
//结果
aa外层
aa中层
aa内层
aa底层
}
}
Lock (display)
package new_course.chp3;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
/**
* @author Created by Lin Weihong
* @date on 2022/6/2 11:21
* 可重入锁
*/
public class SyncLockDemo02 {
public static void main(String[] args) {
//Lock演示可重入锁
Lock lock = new ReentrantLock();
new Thread(() -> {
lock.lock();
try {
System.out.println(Thread.currentThread().getName() + "外层");
new Thread(() -> {
lock.lock();
try {
System.out.println(Thread.currentThread().getName() + "外层");
} catch (Exception e) {
e.printStackTrace();
} finally {
lock.unlock();
}
},"a").start();
} catch (Exception e) {
e.printStackTrace();
} finally {
lock.unlock();
}
},"a").start();
}
}
deadlock
The concept of deadlock
The cause of the deadlock
- Insufficient system resources
- The progress sequence of process running is inappropriate
- Misallocation of resources
Introducing a deadlock scenario
package new_course.chp4;
import java.util.concurrent.TimeUnit;
/**
* @author Created by Lin Weihong
* @date on 2022/6/2 13:02
* 展示死锁
*/
public class DeadLock {
//创建两个对象
static Object a = new Object();
static Object b = new Object();
public static void main(String[] args) {
new Thread(() -> {
synchronized (a) {
System.out.println(Thread.currentThread().getName() + "持有锁a,试图获取锁b");
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
synchronized (b) {
System.out.println(Thread.currentThread().getName() + "获取锁b");
}
}
},"A").start();
new Thread(() -> {
synchronized (b) {
System.out.println(Thread.currentThread().getName() + "持有锁b,试图获取锁a");
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
synchronized (a) {
System.out.println(Thread.currentThread().getName() + "获取锁a");
}
}
},"B").start();
}
}
Verify if it is a deadlock
- jps is similar to linux's ps -ef to display java processes
- jstack comes with jvm, can directly view stack information, stack trace tool