JUC--活跃性
JUC–活跃性
-
JUC–活跃性
-
博主以黑马JUC进行学习
死锁
有这样的情况:一个线程需要同时获取多把锁,这时就容易发生死锁
t1 线程获得 A对象 锁,接下来想获取B 对象的锁
t2 线程获得 B对象 锁,接下来想获取 A对象的锁
例:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23Object A = new Object();
Object B = new Object();
Thread t1 = new Thread(() -> {
synchronized(A){
log.debug("lock A");
sleep(1);
synchronized(B){
log.debug("lock B");
log.debug("操作...");
}
}
},"t1");
Thread t2 = new Thread(() -> {
synchronized(B){
log.debug("lock B");
sleep(0.5);
synchronized(A){
log.debug("lock A");
log.debug("操作...");
}
}
},"t2")定位死锁
- 检测死锁可以使用jconsole工具,或者使用jps定位进程id,再用jstack定位死锁:
1
2
3
4
5
6
7cmd > jps
Picked up JAVA_TOOL_OPTIONS: -Dfile.encoding=UTF-8
12320 Jps
22816 KotlinCompileDaemon
33200 TestDeadLock //JVM 进程
11508 Main
28468 Launcher活锁
活锁出现在两个线程互相改变对方的结束条件,最后谁也无法结束,例如:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24public class TestLiveLock{
static volatile int count = 10;
static final Object lock = new Object();
public static void main(String[] args){
new Thread(() -> {
//期望减到0退出循环
while(count > 0){
sleep(0.2);
count--;
log.debug("count:{}",count);
}
},"t1").start();
new Thread(() -> {
//期望超过20退出循环
while(count < 20){
sleep(0.2);
count++;
log.debug("count:{}",count);
}
},"t2").start();
}
}饥饿
- 某个线程长期得不到 CPU 执行权,或长期抢不到锁,导致任务一直无法执行。
- 常见原因:
- 线程优先级太低
- 其他线程长期占用锁
- 非公平锁导致部分线程永远抢不到
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24// 非公平锁 + 高频率抢锁,低优先级线程可能饥饿
Lock lock = new ReentrantLock(false);
new Thread(()->{
while(true){
lock.lock();
try {
// 长时间占用锁
Thread.sleep(1000);
} finally {
lock.unlock();
}
}
},"高频率抢锁线程").start();
// 这个线程可能永远抢不到锁 → 饥饿
new Thread(()->{
lock.lock();
try {
System.out.println("我执行到了吗?");
} finally {
lock.unlock();
}
},"饥饿线程").start();对比
问题 线程状态 资源占用 结果 死锁 阻塞(BLOCKED) CPU 0% 永久卡住 活锁 运行(RUNNABLE) CPU 100% 永远完不成 饥饿 等待 / 阻塞 CPU 极低 一直得不到执行机会 总结
死锁:互相持有锁,永久阻塞
活锁:互相改条件,一直运行但永远完不成
饥饿:一直抢不到资源,无法执行
都是活跃性失败,会让并发程序无法正常工作