死锁

检测死锁可以使用jconsole工具,或者使用jps定位进程id,再用jstack定位死锁

  1. public class TestDeadLock {
  2. public static void main(String[] args) {
  3. Chopstick c1 = new Chopstick("1");
  4. Chopstick c2 = new Chopstick("2");
  5. Chopstick c3 = new Chopstick("3");
  6. Chopstick c4 = new Chopstick("4");
  7. Chopstick c5 = new Chopstick("5");
  8. new Philosopher("苏格拉底", c1, c2).start();
  9. new Philosopher("柏拉图", c2, c3).start();
  10. new Philosopher("亚里士多德", c3, c4).start();
  11. new Philosopher("赫拉克利特", c4, c5).start();
  12. new Philosopher("阿基米德", c5, c1).start();
  13. }
  14. }
  15. class Philosopher extends Thread {
  16. @Override
  17. public void run() {
  18. while (true) {
  19. // 尝试获得左手筷子
  20. synchronized (left) {
  21. // 尝试获得右手筷子
  22. synchronized (right) {
  23. eat();
  24. }
  25. }
  26. }
  27. }
  28. }
  • 著名的《哲学家就餐》就是死锁

活锁

两个线程不断的运行,但是改变了对方的结束条件,导致无法终止运行,这就叫活锁

  1. public class TestLiveLock {
  2. static volatile int count = 10;
  3. static final Object lock = new Object();
  4. public static void main(String[] args) {
  5. new Thread(() -> {
  6. // 期望减到 0 退出循环
  7. while (count > 0) {
  8. sleep(0.2);
  9. count--;
  10. log.debug("count: {}", count);
  11. }
  12. }, "t1").start();
  13. new Thread(() -> {
  14. // 期望超过 20 退出循环
  15. while (count < 20) {
  16. sleep(0.2);
  17. count++;
  18. log.debug("count: {}", count);
  19. }
  20. }, "t2").start();
  21. }
  22. }
  • 可以通过线程间执行的随机时间来解决活锁问题。

饥饿

很多教程中把饥饿定义为,一个线程由于优先级太低,始终得不到CPU调度执行,也不能够结束
读写锁时会涉及饥饿问题。(todo)

可以通过“按顺序加锁”(链式)来解决饥饿问题

  1. public class TestDeadLock {
  2. public static void main(String[] args) {
  3. Chopstick c1 = new Chopstick("1");
  4. Chopstick c2 = new Chopstick("2");
  5. Chopstick c3 = new Chopstick("3");
  6. Chopstick c4 = new Chopstick("4");
  7. Chopstick c5 = new Chopstick("5");
  8. new Philosopher("苏格拉底", c1, c2).start();
  9. new Philosopher("柏拉图", c2, c3).start();
  10. new Philosopher("亚里士多德", c3, c4).start();
  11. new Philosopher("赫拉克利特", c4, c5).start();
  12. new Philosopher("阿基米德", c1, c5).start(); // 改变了这一行(顺序加锁)
  13. }
  14. }
  15. class Philosopher extends Thread {
  16. @Override
  17. public void run() {
  18. while (true) {
  19. // 尝试获得左手筷子
  20. synchronized (left) {
  21. // 尝试获得右手筷子
  22. synchronized (right) {
  23. eat();
  24. }
  25. }
  26. }
  27. }
  28. }