死锁
检测死锁可以使用jconsole工具,或者使用jps定位进程id,再用jstack定位死锁
public class TestDeadLock {public static void main(String[] args) {Chopstick c1 = new Chopstick("1");Chopstick c2 = new Chopstick("2");Chopstick c3 = new Chopstick("3");Chopstick c4 = new Chopstick("4");Chopstick c5 = new Chopstick("5");new Philosopher("苏格拉底", c1, c2).start();new Philosopher("柏拉图", c2, c3).start();new Philosopher("亚里士多德", c3, c4).start();new Philosopher("赫拉克利特", c4, c5).start();new Philosopher("阿基米德", c5, c1).start();}}class Philosopher extends Thread {@Overridepublic void run() {while (true) {// 尝试获得左手筷子synchronized (left) {// 尝试获得右手筷子synchronized (right) {eat();}}}}}
- 著名的《哲学家就餐》就是死锁
活锁
两个线程不断的运行,但是改变了对方的结束条件,导致无法终止运行,这就叫活锁
public 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调度执行,也不能够结束
读写锁时会涉及饥饿问题。(todo)
可以通过“按顺序加锁”(链式)来解决饥饿问题
public class TestDeadLock {public static void main(String[] args) {Chopstick c1 = new Chopstick("1");Chopstick c2 = new Chopstick("2");Chopstick c3 = new Chopstick("3");Chopstick c4 = new Chopstick("4");Chopstick c5 = new Chopstick("5");new Philosopher("苏格拉底", c1, c2).start();new Philosopher("柏拉图", c2, c3).start();new Philosopher("亚里士多德", c3, c4).start();new Philosopher("赫拉克利特", c4, c5).start();new Philosopher("阿基米德", c1, c5).start(); // 改变了这一行(顺序加锁)}}class Philosopher extends Thread {@Overridepublic void run() {while (true) {// 尝试获得左手筷子synchronized (left) {// 尝试获得右手筷子synchronized (right) {eat();}}}}}
