集合线程安全
1.1、List集合线程不安全演示
import java.util.ArrayList; import java.util.List; import java.util.UUID; public class ThreadDemo4 { public static void main(String[] args) { List<String> list = new ArrayList<>(); for (int i = 0; i < 20; i ) { new Thread(()->{ list.add(UUID.randomUUID().toString().substring(0, 4)); System.out.println(list); },String.valueOf(i)).start(); } } }
执行异常:
1、Vector
2、Collections
3、CopyOnWriteArrayList
import java.util.*; public class ThreadDemo4 { public static void main(String[] args) { List<String> list = new Vector<>(); for (int i = 0; i < 20; i ) { new Thread(()->{ list.add(UUID.randomUUID().toString().substring(0, 4)); System.out.println(list); },String.valueOf(i)).start(); } } }
import java.util.*; public class ThreadDemo4 { public static void main(String[] args) { List<String> list = Collections.synchronizedList(new ArrayList<>()); for (int i = 0; i < 20; i ) { new Thread(()->{ list.add(UUID.randomUUID().toString().substring(0, 4)); System.out.println(list); },String.valueOf(i)).start(); } } }
import java.util.*; import java.util.concurrent.CopyOnWriteArrayList; public class ThreadDemo4 { public static void main(String[] args) { List<String> list = new CopyOnWriteArrayList<>(); for (int i = 0; i < 20; i ) { new Thread(()->{ list.add(UUID.randomUUID().toString().substring(0, 4)); System.out.println(list); },String.valueOf(i)).start(); } } }
public class CopyOnWriteArrayList<E> implements List<E>, RandomAccess, Cloneable, java.io.Serializable { ... final transient ReentrantLock lock = new ReentrantLock(); private transient volatile Object[] array; public CopyOnWriteArrayList() { setArray(new Object[0]); } final void setArray(Object[] a) { array = a; } 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); return true; } finally { lock.unlock(); } }
1.2、HashSet演示线程不安全
import java.util.*; public class ThreadDemo4 { public static void main(String[] args) { Set<String> set = new HashSet<>(); for (int i = 0; i < 20; i ) { new Thread(()->{ set.add(UUID.randomUUID().toString().substring(0, 4)); System.out.println(set); },String.valueOf(i)).start(); } } }
执行异常:
解决方式:
1、CopyOnWriteArraySet
import java.util.*; import java.util.concurrent.CopyOnWriteArraySet; public class ThreadDemo4 { public static void main(String[] args) { Set<String> set = new CopyOnWriteArraySet<>(); for (int i = 0; i < 20; i ) { new Thread(()->{ set.add(UUID.randomUUID().toString().substring(0, 4)); System.out.println(set); },String.valueOf(i)).start(); } } }
1.3、HashMap演示线程不安全
import java.util.*; public class ThreadDemo4 { public static void main(String[] args) { Map<String,String> map = new HashMap<>(); for (int i = 0; i < 20; i ) { String key = String.valueOf(i); new Thread(()->{ map.put(key,UUID.randomUUID().toString().substring(0, 4)); System.out.println(map); },String.valueOf(i)).start(); } } }
执行异常:
解决方式:
1、ConcurrentHashMap
import java.util.*; import java.util.cncurrent.ConcurrentHashMap;
public class ThreadDemo4 {
public static void main(String[] args) {
Map<String,String> map = new ConcurrentHashMap<>();
for (int i = 0; i < 20; i++) {
String key = String.valueOf(i);
new Thread(()->{
map.put(key,UUID.randomUUID().toString().substring(0, 4));
System.out.println(map);
},String.valueOf(i)).start();
}
}
}
二、多线程锁
Synchronized实现同步的基础:Java中每一个对象都可以作为锁。
1、对于普通同步方法,锁是当前实例对象。
2、对于静态同步方法,锁是当前类的class对象。
3、对于同步方法块,锁是Synchronized括号里配置的对象。
2.1、公平锁&非公平锁
public class ReentrantLock implements Lock, java.io.Serializable {
...
public ReentrantLock() {
sync = new NonfairSync();
}
public ReentrantLock(boolean fair) {
sync = fair ? new FairSync() : new NonfairSync();
}
...
static final class NonfairSync extends Sync {
private static final long serialVersionUID = 7316153563782823691L;
/**
* Performs lock. Try immediate barge, backing up to normal
* acquire on failure.
*/
final void lock() {
if (compareAndSetState(0, 1))
setExclusiveOwnerThread(Thread.currentThread());
else
acquire(1);
}
protected final boolean tryAcquire(int acquires) {
return nonfairTryAcquire(acquires);
}
}
static final class FairSync extends Sync {
private static final long serialVersionUID = -3000897897090466540L;
final void lock() {
acquire(1);
}
/**
* Fair version of tryAcquire. Don't grant access unless
* recursive call or no waiters or is first.
*/
protected final boolean tryAcquire(int acquires) {
final Thread current = Thread.currentThread();
int c = getState();
if (c == 0) {
if (!hasQueuedPredecessors() &&
compareAndSetState(0, acquires)) {
setExclusiveOwnerThread(current);
return true;
}
}
else if (current == getExclusiveOwnerThread()) {
int nextc = c + acquires;
if (nextc < 0)
throw new Error("Maximum lock count exceeded");
setState(nextc);
return true;
}
return false;
}
}
有的线程会饿死,优点是。
阳光普照,效率比非公平锁低。公平锁会先去询问一下hasQueuedPredecessors()
2.2、可重入锁
Synchronized和Lock都是可重入锁。
例如:回到家里,只需要把家里的大门打开,家里的卧室门都不需要打开就能自由进入。这就是可重入的意思。
public class ThreadDemo5 {
public static void main(String[] args) {
Object obj = new Object();
new Thread(()-> {
synchronized(obj) {
System.out.println(Thread.currentThread().getName()+" 外层");
synchronized(obj) {
System.out.println(Thread.currentThread().getName()+" 中层");
synchronized(obj) {
System.out.println(Thread.currentThread().getName()+" 内层");
}
}
}
},"t1").start();
}
}
public class ThreadDemo5 {
public synchronized void add() {
add();
}
public static void main(String[] args) {
new ThreadDemo5().add();
}
}
执行上面出现:
2.3、死锁
两个或两个以上进程在执行过程中,因为争夺资源而造成一种相互等待的现象,如果没有外力干涉,他们无法再执行下去,这种现象被称为死锁。
1、系统资源不足
2、进程运行推进顺序不合适
3、资源分配不当
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");
synchronized (b) {
System.out.println(Thread.currentThread().getName() +"持有锁b");
}
}
},"t1").start();
new Thread(() ->{
synchronized (b) {
System.out.println(Thread.currentThread().getName() +"持有锁b,试图获取锁a");
synchronized (a) {
System.out.println(Thread.currentThread().getName() +"持有锁a");
}
}
},"t2").start();
}
}
1.JDK bin目录 jps.exe
2.jstack 进程号
控制台上
--->jps -l 命令
--->jstack 进程号
C:\Users\Administrator>jps -l
7748 com.lwz.study.day04.DeadLock
3768 jdk.jcmd/sun.tools.jps.Jps
5820
C:\Users\Administrator>jstack 7748
2022-04-05 14:08:27
Full thread dump Java HotSpot(TM) 64-Bit Server VM (25.202-b08 mixed mode):
"DestroyJavaVM" #13 prio=5 os_prio=0 tid=0x0000000002532800 nid=0x3600 waiting on condition [0x0000000000000000]
java.lang.Thread.State: RUNNABLE
"t2" #12 prio=5 os_prio=0 tid=0x000000001a61d000 nid=0x3918 waiting for monitor entry [0x000000001afef000]
java.lang.Thread.State: BLOCKED (on object monitor)
at com.lwz.study.day04.DeadLock.lambda$1(DeadLock.java:21)
- waiting to lock <0x00000000d5cbc010> (a java.lang.Object)
- locked <0x00000000d5cbc020> (a java.lang.Object)
at com.lwz.study.day04.DeadLock$$Lambda$2/135721597.run(Unknown Source)
at java.lang.Thread.run(Thread.java:748)
"t1" #11 prio=5 os_prio=0 tid=0x000000001a61b800 nid=0x2a48 waiting for monitor entry [0x000000001aeef000]
java.lang.Thread.State: BLOCKED (on object monitor)
at com.lwz.study.day04.DeadLock.lambda$0(DeadLock.java:13)
- waiting to lock <0x00000000d5cbc020> (a java.lang.Object)
- locked <0x00000000d5cbc010> (a java.lang.Object)
at com.lwz.study.day04.DeadLock$$Lambda$1/531885035.run(Unknown Source)
at java.lang.Thread.run(Thread.java:748)
"Service Thread" #10 daemon prio=9 os_prio=0 tid=0x00000000198c8800 nid=0xc5c runnable [0x0000000000000000]
java.lang.Thread.State: RUNNABLE
"C1 CompilerThread3" #9 daemon prio=9 os_prio=2 tid=0x000000001983a000 nid=0x3834 waiting on condition [0x0000000000000000]
java.lang.Thread.State: RUNNABLE
"C2 CompilerThread2" #8 daemon prio=9 os_prio=2 tid=0x000000001982e000 nid=0x10f8 waiting on condition [0x0000000000000000]
java.lang.Thread.State: RUNNABLE
"C2 CompilerThread1" #7 daemon prio=9 os_prio=2 tid=0x000000001982a000 nid=0x114 waiting on condition [0x0000000000000000]
java.lang.Thread.State: RUNNABLE
"C2 CompilerThread0" #6 daemon prio=9 os_prio=2 tid=0x000000001981f000 nid=0x1c64 waiting on condition [0x0000000000000000]
java.lang.Thread.State: RUNNABLE
"Attach Listener" #5 daemon prio=5 os_prio=2 tid=0x000000001981c800 nid=0x3bac waiting on condition [0x0000000000000000]
java.lang.Thread.State: RUNNABLE
"Signal Dispatcher" #4 daemon prio=9 os_prio=2 tid=0x00000000197c8800 nid=0x1ce4 runnable [0x0000000000000000]
java.lang.Thread.State: RUNNABLE
"Finalizer" #3 daemon prio=8 os_prio=1 tid=0x00000000197b1800 nid=0x8b4 in Object.wait() [0x0000000019d8f000]
java.lang.Thread.State: WAITING (on object monitor)
at java.lang.Object.wait(Native Method)
- waiting on <0x00000000d5c08ed0> (a java.lang.ref.ReferenceQueue$Lock)
at java.lang.ref.ReferenceQueue.remove(ReferenceQueue.java:144)
- locked <0x00000000d5c08ed0> (a java.lang.ref.ReferenceQueue$Lock)
at java.lang.ref.ReferenceQueue.remove(ReferenceQueue.java:165)
at java.lang.ref.Finalizer$FinalizerThread.run(Finalizer.java:216)
"Reference Handler" #2 daemon prio=10 os_prio=2 tid=0x00000000197b0800 nid=0x9c8 in Object.wait() [0x0000000019c8e000]
java.lang.Thread.State: WAITING (on object monitor)
at java.lang.Object.wait(Native Method)
- waiting on <0x00000000d5c06bf8> (a java.lang.ref.Reference$Lock)
at java.lang.Object.wait(Object.java:502)
at java.lang.ref.Reference.tryHandlePending(Reference.java:191)
- locked <0x00000000d5c06bf8> (a java.lang.ref.Reference$Lock)
at java.lang.ref.Reference$ReferenceHandler.run(Reference.java:153)
"VM Thread" os_prio=2 tid=0x00000000179b9800 nid=0x3b90 runnable
"GC task thread#0 (ParallelGC)" os_prio=0 tid=0x0000000002547800 nid=0x3174 runnable
"GC task thread#1 (ParallelGC)" os_prio=0 tid=0x0000000002549000 nid=0x3220 runnable
"GC task thread#2 (ParallelGC)" os_prio=0 tid=0x000000000254a800 nid=0x828 runnable
"GC task thread#3 (ParallelGC)" os_prio=0 tid=0x000000000254c000 nid=0x528 runnable
"GC task thread#4 (ParallelGC)" os_prio=0 tid=0x000000000254f800 nid=0x498 runnable
"GC task thread#5 (ParallelGC)" os_prio=0 tid=0x0000000002550800 nid=0x1344 runnable
"GC task thread#6 (ParallelGC)" os_prio=0 tid=0x0000000002554000 nid=0x1294 runnable
"GC task thread#7 (ParallelGC)" os_prio=0 tid=0x0000000002555000 nid=0x1be4 runnable
"VM Periodic Task Thread" os_prio=2 tid=0x00000000198ee800 nid=0xcb0 waiting on condition
JNI global references: 310
Found one Java-level deadlock:
=============================
"t2":
waiting to lock monitor 0x000000000262bc08 (object 0x00000000d5cbc010, a java.lang.Object),
which is held by "t1"
"t1":
waiting to lock monitor 0x000000000262e6a8 (object 0x00000000d5cbc020, a java.lang.Object),
which is held by "t2"
Java stack information for the threads listed above:
===================================================
"t2":
at com.lwz.study.day04.DeadLock.lambda$1(DeadLock.java:21)
- waiting to lock <0x00000000d5cbc010> (a java.lang.Object)
- locked <0x00000000d5cbc020> (a java.lang.Object)
at com.lwz.study.day04.DeadLock$$Lambda$2/135721597.run(Unknown Source)
at java.lang.Thread.run(Thread.java:748)
"t1":
at com.lwz.study.day04.DeadLock.lambda$0(DeadLock.java:13)
- waiting to lock <0x00000000d5cbc020> (a java.lang.Object)
- locked <0x00000000d5cbc010> (a java.lang.Object)
at com.lwz.study.day04.DeadLock$$Lambda$1/531885035.run(Unknown Source)
at java.lang.Thread.run(Thread.java:748)
Found 1 deadlock.
Java JUC高并发编程(三)-Callable&JUC辅助类