1. 本篇文章主要讲述这四个方法的一些特性,stop()和interrupt()是看冰河大佬笔记中的讲解才尝试验证的。而sleep()和wait()是自己一直想整理的,关于其是否释放CPU以及是否释放锁

1.stop()

强制停止线程

会释放synchronized锁

  1. /**
  2. * stop方法会释放 synchronized
  3. * stop方法不会释放ReentrantLock
  4. */
  5. @Test
  6. public void testStopAndUnRelease() throws InterruptedException {
  7. Object o = new Object();
  8. Runnable runnable = ()->{
  9. synchronized (o){
  10. try {
  11. System.out.println(Thread.currentThread().getName()+":我获取了锁");
  12. TimeUnit.SECONDS.sleep(10);
  13. System.out.println(Thread.currentThread().getName()+":我释放了锁");
  14. } catch (InterruptedException e) {
  15. e.printStackTrace();
  16. }
  17. }
  18. };
  19. Thread thread = new Thread(runnable,"线程A");
  20. Thread thread1 = new Thread(runnable,"线程B");
  21. thread.start();
  22. //确保线程A已获取锁
  23. TimeUnit.SECONDS.sleep(1);
  24. thread1.start();
  25. thread.stop();
  26. System.out.println("线程A已强制停止");
  27. thread.join();
  28. thread1.join();
  29. }

不会主动释放ReetrantLock锁

冰河大佬说不能释放,但是有finally也可以释放的

  1. /**
  2. * 不会释放ReentrantLock
  3. */
  4. @Test
  5. public void testStopAndUnRelease2() throws InterruptedException {
  6. ReentrantLock lock = new ReentrantLock();
  7. Runnable runnable = () -> {
  8. lock.lock();
  9. try {
  10. System.out.println(Thread.currentThread().getName() + ":我获取了锁");
  11. TimeUnit.SECONDS.sleep(10);
  12. System.out.println(Thread.currentThread().getName() + ":我释放了锁");
  13. } catch (InterruptedException e) {
  14. e.printStackTrace();
  15. }
  16. lock.unlock();
  17. };
  18. Thread thread = new Thread(runnable, "线程A");
  19. Thread thread1 = new Thread(runnable, "线程B");
  20. thread.start();
  21. TimeUnit.SECONDS.sleep(1);
  22. thread1.start();
  23. thread.stop();
  24. System.out.println("线程A已强制停止");
  25. thread.join();
  26. thread1.join();
  27. }
  28. /**
  29. * ReentrantLock会释放
  30. */
  31. @Test
  32. public void testStopAndUnRelease2() throws InterruptedException {
  33. ReentrantLock lock = new ReentrantLock();
  34. Runnable runnable = () -> {
  35. lock.lock();
  36. try {
  37. System.out.println(Thread.currentThread().getName() + ":我获取了锁");
  38. TimeUnit.SECONDS.sleep(10);
  39. System.out.println(Thread.currentThread().getName() + ":我释放了锁");
  40. } catch (InterruptedException e) {
  41. e.printStackTrace();
  42. }finally {
  43. lock.unlock();
  44. }
  45. };
  46. Thread thread = new Thread(runnable, "线程A");
  47. Thread thread1 = new Thread(runnable, "线程B");
  48. thread.start();
  49. TimeUnit.SECONDS.sleep(1);
  50. thread1.start();
  51. thread.stop();
  52. System.out.println("线程A已强制停止");
  53. thread.join();
  54. thread1.join();
  55. }

2.interrupt()

标记线程中断

需要代码里主动检测

触发InterruptedException

  • wait
  • join
  • sleep

    3.sleep()

    关于sleep()的两个问题分别是:

  • 会释放锁吗? 答:不会

  • 会释放CPU吗? 答:会

    不会释放锁

    1. /**
    2. * 不会放弃锁
    3. * @throws InterruptedException
    4. */
    5. @Test
    6. public void testSleepIsReleaseLock() throws InterruptedException {
    7. Object o = new Object();
    8. Runnable runnable = ()->{
    9. System.out.println("外层"+Thread.currentThread().getName());
    10. synchronized (o){
    11. System.out.println(Thread.currentThread().getName());
    12. try {
    13. TimeUnit.SECONDS.sleep(10);
    14. } catch (InterruptedException e) {
    15. e.printStackTrace();
    16. }
    17. System.out.println(Thread.currentThread().getName()+":我结束了");
    18. }
    19. };
    20. Thread threadA = new Thread(runnable, "线程A");
    21. threadA.start();
    22. TimeUnit.SECONDS.sleep(1);
    23. System.err.println("开始创建并执行线程B,当前的线程A状态"+threadA.getState());
    24. Thread threadB = new Thread(runnable, "线程B");
    25. threadB.start();
    26. threadA.join();
    27. threadB.join();
    28. }
  • 线程A先启动等待1秒后启动线程B,此时线程A已经获取锁

  • 线程B仅仅打印锁外的 外层信息就是卡住了
  • 待A解锁打印结束后,线程B才会进入打印自己的线程名->sleep->释放锁

    会释放CPU

    1. /**
    2. * 测试Sleep是否放弃锁和CPU
    3. * 1.会放弃CPU,但是我电脑多核的也不准,结合JVM3书上所说
    4. */
    5. @Test
    6. public void testSleepIsReleaseAll() throws InterruptedException {
    7. Runnable runnable = ()->{
    8. System.out.println(Thread.currentThread().getName());
    9. try {
    10. TimeUnit.SECONDS.sleep(10);
    11. } catch (InterruptedException e) {
    12. e.printStackTrace();
    13. }
    14. System.out.println(Thread.currentThread().getName()+":我结束了");
    15. };
    16. Thread threadA = new Thread(runnable, "线程A");
    17. threadA.start();
    18. TimeUnit.SECONDS.sleep(1);
    19. System.err.println("开始创建并执行线程B,当前的线程A状态"+threadA.getState());
    20. Thread threadB = new Thread(runnable, "线程B");
    21. threadB.start();
    22. threadA.join();
    23. threadB.join();
    24. }
  • 线程A先启动,等一秒后启动的线程B,此时主线程打印了线程A状态为 Timed-Waited

  • 线程B启动后,也立即打印,并进入sleep

    从实验中其实说明不了什么,因为我的电脑是多核的,线程A可能还一直占着A核心,B去用CPU的B核心也说不定。所以。这里我只能相信《深入理解JVM》的作者了。书上说: image.png 那就是不占CPU

4.wait()

对wait()一直很迷糊

  • 是否释放锁? 释放
  • 是否释放CPU?释放
  • 在哪里可以调用wait()?**synchronized**使用的对象,才可以调用**wait()**
  • 程序调用完wait(),如何唤醒,唤醒完程序从哪里运行? 唤醒后从**wait()**那行紧接着运行

    释放锁

    1. @Test
    2. public void testWait() throws InterruptedException {
    3. Object o = new Object();
    4. Runnable runnable = ()->{
    5. synchronized (o){
    6. System.out.println(Thread.currentThread().getName());
    7. try {
    8. o.wait();
    9. } catch (InterruptedException e) {
    10. e.printStackTrace();
    11. }
    12. System.out.println(Thread.currentThread().getName()+":我结束了");
    13. }
    14. };
    15. Thread threadA = new Thread(runnable, "线程A");
    16. threadA.start();
    17. TimeUnit.SECONDS.sleep(1);
    18. System.err.println("开始创建并执行线程B,当前的线程A状态"+threadA.getState());
    19. Thread threadB = new Thread(runnable, "线程B");
    20. threadB.start();
    21. threadA.join();
    22. threadB.join();
    23. }
  • 线程A先运行,之后调用wait

  • 主线程打印线程A状态会为Waited,并开启B
  • 如果不释放锁,B线程启动后名字是打不出来的,但是B启动后立即打印了B线程名

    释放CPU

    我相信周志明大佬

    只有被synchronized()的对象可以调

    我在最初学习多线程的时候看到最多就是,synchronized中直接调用wait()。但是下面这个程序这样调会出现异常的。
    1. @Test
    2. public void testWait() throws InterruptedException {
    3. Object o = new Object();
    4. Runnable runnable = ()->{
    5. synchronized (o){
    6. System.out.println(Thread.currentThread().getName());
    7. try {
    8. wait();
    9. } catch (InterruptedException e) {
    10. e.printStackTrace();
    11. }
    12. System.out.println(Thread.currentThread().getName()+":我结束了");
    13. }
    14. };
    15. Thread threadA = new Thread(runnable, "线程A");
    16. threadA.start();
    17. TimeUnit.SECONDS.sleep(1);
    18. System.err.println("开始创建并执行线程B,当前的线程A状态"+threadA.getState());
    19. Thread threadB = new Thread(runnable, "线程B");
    20. threadB.start();
    21. threadA.join();
    22. threadB.join();
    23. }
    image.png

    当时学习的时候调用可以,因为

    1. 如果synchronized在实例方法上,synchronized锁的是this实例,方法中wait(),自然是this.wait()。
    2. 如果synchronized是synchronized(this){…},这样也没问题
    3. 如果synchronized是在static方法上,大家可以试一下,可以使用该类字节码对象的wait()方法
  1. public class MyTest{
  2. public static void sayHello() throws InterruptedException {
  3. MyTest.class.wait();
  4. }
  5. }

从wait()那行继续往下运行

这个想必不用解释吧!

  1. /**
  2. *
  3. */
  4. @Test
  5. public void testWaitTime() throws InterruptedException {
  6. Object o = new Object();
  7. Runnable runnable = ()->{
  8. int i=0;
  9. System.out.println("外层"+Thread.currentThread().getName());
  10. synchronized (o){
  11. System.out.println(Thread.currentThread().getName());
  12. try {
  13. if (i==0){
  14. System.out.println("waitxxx");
  15. o.wait(1000);
  16. }
  17. } catch (InterruptedException e) {
  18. e.printStackTrace();
  19. }
  20. System.out.println(Thread.currentThread().getName()+":我结束了");
  21. }
  22. };
  23. Thread threadA = new Thread(runnable, "线程A");
  24. threadA.start();
  25. TimeUnit.SECONDS.sleep(1);
  26. System.err.println("开始创建并执行线程B,当前的线程A状态"+threadA.getState());
  27. Thread threadB = new Thread(runnable, "线程B");
  28. threadB.start();
  29. threadA.join();
  30. threadB.join();
  31. }
  • i永远都是0,但是wait()走完就往下走的,线程会终止