jstack查看死锁
多个线程共同去抢多个锁的时候,容易出现死锁,通过jstack命令可以查看死锁。
jstack pid
线程通讯
wait,notify, nofityAll是和同步synchronized一同使用的, wait的意思就是当前线程放弃了这个锁
单生产者消费者
public class SimpleProducerAndConsumer {
private final Object LOCK = new Object();
// 生产和消费的数据
private Integer index = 0;
// 判断生产状态
private volatile boolean isProduced = false;
public void produce(){
synchronized(LOCK){
if(isProduced){
try {
LOCK.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}else{
index++;
System.out.println("P->" + index);
LOCK.notify();
isProduced = true;
}
}
}
public void consume(){
synchronized(LOCK){
if(isProduced){
System.out.println("C->" + index);
LOCK.notify();
isProduced = false;
}else{
try {
LOCK.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
public static void main(String[] args) {
SimpleProducerAndConsumer simple = new SimpleProducerAndConsumer();
new Thread(() -> {
while (true) {
simple.produce();
}
}).start();
new Thread(() -> {
while (true) {
simple.consume();
}
}).start();
}
}
多生产者消费者
notify是唤醒除了此线程之外的其他所有线程的任意一个, 如果多个生产者多个消费者,消费者可能会唤醒另外一个消费者, 结果最后生产者消费者都wait住了,就会出现假死现象,多个生产者消费者要用notifyAll, 会唤醒所有wait的线程
import java.util.stream.Stream;
public class SimpleProducerAndConsumer {
private final Object LOCK = new Object();
// 生产和消费的数据
private Integer index = 0;
// 判断生产状态
private volatile boolean isProduced = false;
public void produce() {
synchronized (LOCK) {
if (isProduced) {
try {
LOCK.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
} else {
index++;
System.out.println(Thread.currentThread().getName() + "---------------------------------------------->" + index);
LOCK.notifyAll();
isProduced = true;
}
}
}
public void consume() {
synchronized (LOCK) {
if (isProduced) {
System.out.println(Thread.currentThread().getName() + "->" + index);
LOCK.notifyAll();
isProduced = false;
} else {
try {
LOCK.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
public static void main(String[] args) {
SimpleProducerAndConsumer simple = new SimpleProducerAndConsumer();
Stream.of("P1", "P2", "P3", "P4").forEach(n -> new Thread(() -> {
while (true) {
simple.produce();
try {
Thread.sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}, n).start());
Stream.of("C1", "C2", "C3").forEach(n -> new Thread(() -> {
while (true) {
simple.consume();
try {
Thread.sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}, n).start());
}
}
wait set
- 每个对象都有wait set的概念, 存放该对象wait方法之后进入block状态的线程
- 线程notify之后进入runnable状态, 并不一定立即执行
- 线程从wait set中被唤醒顺序是不确定的
- 线程被唤醒后, 会重新获取锁, 代码从wait后面开始执行
package com.mine;
import java.util.Optional;
import java.util.stream.IntStream;
public class WaitSet {
private static final Object LOCK = new Object();
public static void main(String[] args) {
IntStream.rangeClosed(1, 10).forEach(i ->
new Thread(() -> {
synchronized(LOCK){
Optional.of(Thread.currentThread().getName() + " 进入wait set").ifPresent(System.out::println);
try {
LOCK.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
Optional.of(Thread.currentThread().getName() + " 离开wait set").ifPresent(System.out::println);
}
}, String.valueOf(i)).start()
);
try {
Thread.sleep(10_000);
} catch (InterruptedException e) {
e.printStackTrace();
}
// 一个一个的唤醒线程
synchronized(LOCK){
IntStream.rangeClosed(1, 10).forEach(
i -> LOCK.notify()
);
}
}
}
输出结果为:
2 进入wait set
10 进入wait set
9 进入wait set
8 进入wait set
7 进入wait set
6 进入wait set
4 进入wait set
5 进入wait set
3 进入wait set
1 进入wait set
2 离开wait set
1 离开wait set
3 离开wait set
5 离开wait set
4 离开wait set
6 离开wait set
7 离开wait set
8 离开wait set
9 离开wait set
10 离开wait set