zoukankan      html  css  js  c++  java
  • 多线程的创建、停止

    1、多线程的创建方式 

    • 继承Thread类
    • 实现runnable 接口,无返回值,无异常
    • 实现callable接口,有返回值,有异常
    • 线程池(此种方式,网上很多不算创建方式,但是个人觉得可以创建线程,所以我归进去)

    1、1 继承Thread类

      

      public static class MyThread extends Thread{
    
        @Override
        public void run(){
    
          System.out.println("继承Thread");
        }
    
      }

    1、2 实现runnable接口

      

      public static class UseRunnable implements Runnable {
    
        @Override
        public void run() {
          System.out.println("i am runbable impl");
        }
      }

    1、3 实现callable接口

     public static class UseCall implements Callable<String> {
    
        @Override
        public String call() throws Exception {
          return "Callable";
        }
      }

    1、4 main方法调用

     public static void main(String[] args) {
    
        UseRunnable useRunnable = new UseRunnable();
        new Thread(useRunnable).start();
        /**
         *因为 Tread 源码中,不直接支持callable的方式,因此直接传入callable 是报错
         *new Thread(useCall).start();
         *以下为源码
         * public Thread(Runnable target) {
         *   init(null, target, "Thread-" + nextThreadNum(), 0);
         *}
         */
        UseCall useCall = new UseCall();
        FutureTask<String> futureTask = new FutureTask<>(useCall);
        new Thread(futureTask).start();
        String s = null;//就是callable 的返回
        try {
          s = futureTask.get(); //get方法是阻塞的
        } catch (InterruptedException e) {
          e.printStackTrace();
        } catch (ExecutionException e) {
          e.printStackTrace();
        }
        System.out.println(s);
      }

    注:几个线程的创建类,都用了static,是为了让我在main方法中使用

    2、线程的停止

    • 使用退出标志,使线程正常退出,也就是当 run() 方法完成后线程中止。
    • 使用 stop(),resume(),suspend() 方法强行终止线程,但是不推荐使用这个方法,该方法已被弃用。此方法不释放资源
    • interrupt() isInterrupted() ;static interrupted() ,这些方法都在Thread类中

    2、1 继承类中使用

     public static class EndThread extends Thread {
        public EndThread(String name) {
          super(name);
        }
        @Override
        public void run() {
          String threadName = Thread.currentThread().getName();
    
    //        while (true){ //如果此处 不对标记位进行处理 则不会中断
    //          System.out.println(String.format("线程【%S】,正在运行",threadName));
    //
    //        }
          while (!interrupted()) { //如果此处 不对标记位进行处理 则不会中断
            System.out.println(String.format("线程【%S】,正在运行", threadName));
          }
          System.out.println(String.format("线程【%S】的中断状态%S", threadName, interrupted()));
        }
    
      }

    2、2 实现类中使用,此处只展示Runnable

    /**
       * interrupted() 等方法是在Thread中存在,Runnable中不存在
       * 下面演示如何在runnable中使用
       */
    
    
      public static class EndAble implements Runnable{
    
        @Override
        public void run() {
          String threadName = Thread.currentThread().getName();
    
          while (!Thread.currentThread().isInterrupted()) { //如果此处 不对标记位进行处理 则不会中断
            System.out.println(String.format("线程【%S】,正在运行", threadName));
          }
          System.out.println(String.format("线程【%S】的中断状态%S", threadName, Thread.interrupted()));
        }
      }

    2、3 main方法中运行

     public static void main(String[] args) {
        Thread endThread = new EndThread("endThread");
        endThread.start();
    
        try {
          Thread.sleep(2000); //停止是为了,监控中断状态
          endThread.interrupt();
        } catch (InterruptedException e) {
          e.printStackTrace();
        }
      }
    线程【ENDTHREAD】,正在运行
    线程【ENDTHREAD】,正在运行
    线程【ENDTHREAD】,正在运行
    线程【ENDTHREAD】,正在运行
    线程【ENDTHREAD】,正在运行
    线程【ENDTHREAD】,正在运行
    线程【ENDTHREAD】,正在运行
    线程【ENDTHREAD】,正在运行
    线程【ENDTHREAD】,正在运行
    线程【ENDTHREAD】,正在运行
    线程【ENDTHREAD】,正在运行
    线程【ENDTHREAD】的中断状态FALSE

     3、线程发生InterruptedException异常时的停止

    package org.hxm.thread.Demo1;
    
    /**
     * @author : Aaron
     *
     * create at:  2020/9/7  12:16
     *
     * description: 异常
     */
    public class HasInterruptedException {
    
      public static class UseThread extends Thread {
    
        @Override
        public void run() {
          String threadName = Thread.currentThread().getName();
          while (!isInterrupted()) {
    
            try {
              Thread.sleep(100);
            } catch (InterruptedException e) {
              System.out.println(String.format("发生了异常,当前的标志位位:[%S]", isInterrupted()));
              e.printStackTrace();
            }
            System.out.println(String.format("当前线程的名称是,【%S】", threadName));
          }
          System.out.println(
              String.format("线程【%S】的中断状态%S", threadName, Thread.currentThread().isInterrupted()));
    
        }
      }
    
      public static void main(String[] args) throws InterruptedException {
        UseThread useThread = new UseThread();
        useThread.start();
        Thread.sleep(500);
        useThread.interrupt();
      }
    
    }

    运行此方法,发现线程会一直执行,停不下来,没有打印自线程while 外面的一句话。原因就是:线程发生interruped异常时,会把标记位复原(false)

    当前线程的名称是,【THREAD-0】
    当前线程的名称是,【THREAD-0】
    当前线程的名称是,【THREAD-0】
    当前线程的名称是,【THREAD-0】
    发生了异常,当前的标志位位:[FALSE]
    当前线程的名称是,【THREAD-0】
    java.lang.InterruptedException: sleep interrupted
        at java.lang.Thread.sleep(Native Method)
        at org.hxm.thread.Demo1.HasInterruptedException$UseThread.run(HasInterruptedException.java:20)
    当前线程的名称是,【THREAD-0】
    当前线程的名称是,【THREAD-0】
    当前线程的名称是,【THREAD-0】
    当前线程的名称是,【THREAD-0】
    当前线程的名称是,【THREAD-0】
    当前线程的名称是,【THREAD-0】
    当前线程的名称是,【THREAD-0】
    当前线程的名称是,【THREAD-0】
    当前线程的名称是,【THREAD-0】
    当前线程的名称是,【THREAD-0】
    当前线程的名称是,【THREAD-0】
    当前线程的名称是,【THREAD-0】
    当前线程的名称是,【THREAD-0】
    当前线程的名称是,【THREAD-0】
    当前线程的名称是,【THREAD-0】
    当前线程的名称是,【THREAD-0】
    当前线程的名称是,【THREAD-0】
    当前线程的名称是,【THREAD-0】
    当前线程的名称是,【THREAD-0】
    当前线程的名称是,【THREAD-0】
    当前线程的名称是,【THREAD-0】
    当前线程的名称是,【THREAD-0】
    当前线程的名称是,【THREAD-0】

    正确停止此类线程的方法

    public static class UseThread extends Thread {
    
        @Override
        public void run() {
          String threadName = Thread.currentThread().getName();
          while (!isInterrupted()) {
    
            try {
              Thread.sleep(100);
            } catch (InterruptedException e) {
              System.out.println(String.format("发生了异常,当前的标志位位:[%S]", isInterrupted()));
              interrupt();//需要在异常里面在执行停止
              e.printStackTrace();
            }
            System.out.println(String.format("当前线程的名称是,【%S】", threadName));
          }
          System.out.println(
              String.format("线程【%S】的中断状态%S", threadName, Thread.currentThread().isInterrupted()));
    
        }
      }

    4、理解线程中的start() 和 run()

    package org.hxm.thread.Demo1;
    
    /**
     * @author : Aaron
     *
     * create at:  2020/9/7  12:48
     *
     * description: 理解Start和run
     */
    public class StartAndRun {
    
    
      public static class MyThread extends Thread{
    
        @Override
        public void run(){
          int i =100;
          while (i>0){
            System.out.println(String.format("线程【%S】,正在运行,当前的i=【%S】", Thread. currentThread().getName(),i--));
          }
        }
      }
    
      public static void main(String[] args) {
        MyThread myThread =  new MyThread();
        myThread.setName("xxxxxxxx");
        myThread.run();
      }
    }

    打印结果

    线程【MAIN】,正在运行,当前的i=【100】
    线程【MAIN】,正在运行,当前的i=【99】
    线程【MAIN】,正在运行,当前的i=【98】
    线程【MAIN】,正在运行,当前的i=【97】
    线程【MAIN】,正在运行,当前的i=【96】
    线程【MAIN】,正在运行,当前的i=【95】
    线程【MAIN】,正在运行,当前的i=【94】
    线程【MAIN】,正在运行,当前的i=【93】
    线程【MAIN】,正在运行,当前的i=【92】
    线程【MAIN】,正在运行,当前的i=【91】
    线程【MAIN】,正在运行,当前的i=【90】
    线程【MAIN】,正在运行,当前的i=【89】
    线程【MAIN】,正在运行,当前的i=【88】
    线程【MAIN】,正在运行,当前的i=【87】
    线程【MAIN】,正在运行,当前的i=【86】
    线程【MAIN】,正在运行,当前的i=【85】
    线程【MAIN】,正在运行,当前的i=【84】
    线程【MAIN】,正在运行,当前的i=【83】
    线程【MAIN】,正在运行,当前的i=【82】
    线程【MAIN】,正在运行,当前的i=【81】
    线程【MAIN】,正在运行,当前的i=【80】
    线程【MAIN】,正在运行,当前的i=【79】
    线程【MAIN】,正在运行,当前的i=【78】
    线程【MAIN】,正在运行,当前的i=【77】
    线程【MAIN】,正在运行,当前的i=【76】
    线程【MAIN】,正在运行,当前的i=【75】
    线程【MAIN】,正在运行,当前的i=【74】
    线程【MAIN】,正在运行,当前的i=【73】
    线程【MAIN】,正在运行,当前的i=【72】
    线程【MAIN】,正在运行,当前的i=【71】
    线程【MAIN】,正在运行,当前的i=【70】
    线程【MAIN】,正在运行,当前的i=【69】
    线程【MAIN】,正在运行,当前的i=【68】
    线程【MAIN】,正在运行,当前的i=【67】
    线程【MAIN】,正在运行,当前的i=【66】
    线程【MAIN】,正在运行,当前的i=【65】
    线程【MAIN】,正在运行,当前的i=【64】
    线程【MAIN】,正在运行,当前的i=【63】
    线程【MAIN】,正在运行,当前的i=【62】
    线程【MAIN】,正在运行,当前的i=【61】
    线程【MAIN】,正在运行,当前的i=【60】
    线程【MAIN】,正在运行,当前的i=【59】
    线程【MAIN】,正在运行,当前的i=【58】
    线程【MAIN】,正在运行,当前的i=【57】
    线程【MAIN】,正在运行,当前的i=【56】
    线程【MAIN】,正在运行,当前的i=【55】
    线程【MAIN】,正在运行,当前的i=【54】
    线程【MAIN】,正在运行,当前的i=【53】
    线程【MAIN】,正在运行,当前的i=【52】
    线程【MAIN】,正在运行,当前的i=【51】
    线程【MAIN】,正在运行,当前的i=【50】
    线程【MAIN】,正在运行,当前的i=【49】
    线程【MAIN】,正在运行,当前的i=【48】
    线程【MAIN】,正在运行,当前的i=【47】
    线程【MAIN】,正在运行,当前的i=【46】
    线程【MAIN】,正在运行,当前的i=【45】
    线程【MAIN】,正在运行,当前的i=【44】
    线程【MAIN】,正在运行,当前的i=【43】
    线程【MAIN】,正在运行,当前的i=【42】
    线程【MAIN】,正在运行,当前的i=【41】
    线程【MAIN】,正在运行,当前的i=【40】
    线程【MAIN】,正在运行,当前的i=【39】
    线程【MAIN】,正在运行,当前的i=【38】
    线程【MAIN】,正在运行,当前的i=【37】
    线程【MAIN】,正在运行,当前的i=【36】
    线程【MAIN】,正在运行,当前的i=【35】
    线程【MAIN】,正在运行,当前的i=【34】
    线程【MAIN】,正在运行,当前的i=【33】
    线程【MAIN】,正在运行,当前的i=【32】
    线程【MAIN】,正在运行,当前的i=【31】
    线程【MAIN】,正在运行,当前的i=【30】
    线程【MAIN】,正在运行,当前的i=【29】
    线程【MAIN】,正在运行,当前的i=【28】
    线程【MAIN】,正在运行,当前的i=【27】
    线程【MAIN】,正在运行,当前的i=【26】
    线程【MAIN】,正在运行,当前的i=【25】
    线程【MAIN】,正在运行,当前的i=【24】
    线程【MAIN】,正在运行,当前的i=【23】
    线程【MAIN】,正在运行,当前的i=【22】
    线程【MAIN】,正在运行,当前的i=【21】
    线程【MAIN】,正在运行,当前的i=【20】
    线程【MAIN】,正在运行,当前的i=【19】
    线程【MAIN】,正在运行,当前的i=【18】
    线程【MAIN】,正在运行,当前的i=【17】
    线程【MAIN】,正在运行,当前的i=【16】
    线程【MAIN】,正在运行,当前的i=【15】
    线程【MAIN】,正在运行,当前的i=【14】
    线程【MAIN】,正在运行,当前的i=【13】
    线程【MAIN】,正在运行,当前的i=【12】
    线程【MAIN】,正在运行,当前的i=【11】
    线程【MAIN】,正在运行,当前的i=【10】
    线程【MAIN】,正在运行,当前的i=【9】
    线程【MAIN】,正在运行,当前的i=【8】
    线程【MAIN】,正在运行,当前的i=【7】
    线程【MAIN】,正在运行,当前的i=【6】
    线程【MAIN】,正在运行,当前的i=【5】
    线程【MAIN】,正在运行,当前的i=【4】
    线程【MAIN】,正在运行,当前的i=【3】
    线程【MAIN】,正在运行,当前的i=【2】
    线程【MAIN】,正在运行,当前的i=【1】

    通过打印结果可以看出,run方法并没有创建线程,当前只是讲MyThread当作一个java对象,执行的是java对象中的run方法。所以 打印出来的线程名称是main ,并不是set的线程名称XXX

  • 相关阅读:
    XP和Scrum的比较
    让PowerDesigner支持SQLite 3.0[转]
    对于大型公司项目平台选择j2ee的几层认识(一)
    对于大型公司项目平台选择j2ee的几层认识(三)
    Alpha、Beta、RC、GA版本的区别
    如何在XElement中使用XPath
    对于大型公司项目平台选择j2ee的几层认识(四)
    Thread与BeginInvoke
    对于大型公司项目平台选择j2ee的几层认识(二)
    修复VS 2010的Help Library管理器
  • 原文地址:https://www.cnblogs.com/JavaHxm/p/13626102.html
Copyright © 2011-2022 走看看