zoukankan      html  css  js  c++  java
  • 线程的交互及其相关

    线程的中断

    因为线程中的stop()方法,已经被弃用,因为它是不安全的,使用它相当于你在家用电脑,直接在没有预知的情况下直接给你停电了一样,太暴力,所以不能用它。应该用 interrupt()这个不是直接中断,而是将当前线程标志为中断标记,只是一个标记。怎么用,代码示例如下:

     1 package com.huolongluo.coindemo.thread;
     2 
     3 /**
     4  * Created by 火龙裸 on 2019/11/13.
     5  * desc   : 线程的中断
     6  * version: 1.0
     7  */
     8 public class ThreadDemo {
     9     public static void main(String[] args) {
    10         MyThread myThread = new MyThread();
    11         myThread.start();//启动子线程
    12 
    13         try {
    14             Thread.sleep(500);//当前工作的那个线程(主线程)沉睡500毫秒(也就是让子线程跑500毫秒钟)
    15         } catch (InterruptedException e) {
    16             e.printStackTrace();
    17         }
    18 //        myThread.stop();//不安全,已被弃用
    19         myThread.interrupt();//主线程沉睡500毫秒后,继续在主线程当中,通过“myThread”对象,将子线程标记为中断,
    20     }
    21 }
    22 
    23 class MyThread extends Thread {
    24     @Override
    25     public void run() {
    26         for (int i = 0; i < 1000000; i++) {
    27             //(Thread.interrupted()返回当前线程(这个代码所运行的那个线程)标志位(当前代码所运行在的那个线程状态),并将标志位重置
    28             if (Thread.interrupted()) {//也可以使用isInterrupted(),判断当前线程(这个代码所运行的那个线程)标志位,但isInterrupted()不会重置标志位
    29                 //收尾工作
    30                 return;
    31             }
    32             System.out.println("number: " + i);
    33         }
    34     }
    35 }

    注意:Thread.interrupted()是个静态方法,和直接使用isInterrupted()是有区别的。虽然都会返回当前代码执行的那个线程的线程状态,但是Thread.interrupted()还会同时将标志位重置为false。

    另外一种情况,当子线程有沉睡/等待操作,主线程当中通过子线程对象调用了interrupt()方法,将子线程的线程标志为标记为中断,因为子线程有睡眠,所以会先抛出子线程的异常,而不是执行判断Thread.interrupted()判断,这个时候所以收尾工作应该在子线程中的e.printStackTrace();之后,子线程所抛出的InterruptedException异常,也会将自己的线程中断状态标志位重置为false,所以要是没有在子线程的e.printStackTrace()之后做收尾工作,相当于没有中断,仍旧会一直循环执行下去。因为这个时候子线程在休眠,为了避免浪费资源,收尾工作需要在子线程抛异常的那个位置。

    代码示例如下:

     1 package com.huolongluo.coindemo.thread;
     2 
     3 /**
     4  * Created by 火龙裸 on 2019/11/13.
     5  * desc   : 线程的中断
     6  * version: 1.0
     7  */
     8 public class ThreadDemo {
     9     public static void main(String[] args) {
    10         MyThread myThread = new MyThread();
    11         myThread.start();//启动子线程
    12 
    13         try {
    14             Thread.sleep(500);//当前工作的那个线程(主线程)沉睡500毫秒(也就是让子线程跑500毫秒钟)
    15         } catch (InterruptedException e) {
    16             e.printStackTrace();
    17         }
    18 //        myThread.stop();//不安全,已被弃用
    19         myThread.interrupt();//主线程沉睡500毫秒后,继续在主线程当中,通过“myThread”对象,将子线程标记为中断,
    20     }
    21 }
    22 
    23 class MyThread extends Thread {
    24     @Override
    25     public void run() {
    26         for (int i = 0; i < 1000000; i++) {
    27             //(Thread.interrupted()返回当前线程(这个代码所运行的那个线程)标志位(当前代码所运行在的那个线程状态),并将标志位重置
    28             if (Thread.interrupted()) {//也可以使用isInterrupted(),判断当前线程(这个代码所运行的那个线程)标志位,但isInterrupted()不会重置标志位
    29                 System.out.println("判断标志位");
    30                 //收尾工作
    31                 return;
    32             }
    33             try {
    34                 Thread.sleep(2000);//当前子线程沉睡2秒
    35             } catch (InterruptedException e) {//InterruptedException异常,也会将标志位重置
    36                 e.printStackTrace();
    37                 //收尾工作
    38                 System.out.println("子线程 收尾啦");
    39                 return;
    40             }
    41             System.out.println("number: " + i);
    42         }
    43     }
    44 }

    运行结果:

    还有一种,睡眠方式:SystemClock.sleep(2000),它与Sleep(2000)的区别是,SystemClock.sleep(2000)把InterruptedException异常给吃掉了,它不会抛异常,所以也不会重置标志位,只是单纯的让当前线程睡2秒钟。示例代码如下:

    运行结果:

    只打印一行,然后再return结束掉了。

    线程的等待

    线程交互中,也经常会用到等待wait(),但其实wait()方法和notifyAll()方法都是一个Object类中的方法。代码示例如下:

     1 package com.huolongluo.coindemo.thread;
     2 
     3 /**
     4  * Created by 火龙裸 on 2019/11/16.
     5  * desc   : 线程等待wait()
     6  * version: 1.0
     7  */
     8 public class ThreadDemo2 {
     9     public static void main(String[] args) {
    10         WaitDemo waitDemo = new WaitDemo();
    11         waitDemo.runTest();
    12     }
    13 }
    14 
    15 interface TestDemo {
    16     void runTest();
    17 }
    18 
    19 class WaitDemo implements TestDemo {
    20     private String str;
    21 
    22     @Override
    23     public void runTest() {
    24         Thread thread1 = new Thread(new Runnable() {
    25             @Override
    26             public void run() {
    27                 try {
    28                     Thread.sleep(1000);
    29                 } catch (InterruptedException e) {
    30                     e.printStackTrace();
    31                 }
    32                 initStr();//初始化字符串
    33             }
    34         });
    35         thread1.start();
    36 
    37         Thread thread2 = new Thread(new Runnable() {
    38             @Override
    39             public void run() {
    40                 try {
    41                     Thread.sleep(500);
    42                 } catch (InterruptedException e) {
    43                     e.printStackTrace();
    44                 }
    45                 printStr();//打印字符串
    46             }
    47         });
    48         thread2.start();
    49     }
    50 
    51     private synchronized void initStr() {
    52         str = "火龙裸";
    53         System.out.println("初始化完成");
    54         notifyAll();
    55     }
    56 
    57     private synchronized void printStr() {
    58         while (str == null) {
    59             System.out.println("循环中");
    60             try {
    61                 wait();//释放锁,进入到等待队列
    62             } catch (InterruptedException e) {
    63                 e.printStackTrace();
    64             }
    65         }
    66         System.out.println("打印结果: " + str);
    67     }
    68 }

    运行结果:

    结果正是我想要的。但是假如在printStr()方法中,去掉wait()方法,其他代码不动,则会出现永远一直打印“循环中”,就算直到1秒后,也不会执行“初始化initStr()方法”。因为那个monitor,锁一直被thread2所持有没被释放。这里面调用wait()方法后,线程是进入到等待队列(先进先出),被唤醒后,依旧排队执行,以队列的形式,排在唤醒(主叫)的那个线程后面。还有wait()方法和notifyAll()方法都是必须要写到synchronized里面,要是没有被synchronized包裹,去执行的时候,会报错,所以必须是这样写。

  • 相关阅读:
    面向对象之多态,property
    描述符
    day23 面向对象之继承
    day22面向对象
    os模块
    logging日志模块,四种方式
    Linux 如何测试 IO 性能(磁盘读写速度)
    Vi命令:如何删除全部内容
    cdnbest如何查看站点操作日志(同步日志)
    Linux查找含有某字符串的所有文件
  • 原文地址:https://www.cnblogs.com/huolongluo/p/11854124.html
Copyright © 2011-2022 走看看