多线程的创建、停止

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

原文地址:https://www.cnblogs.com/JavaHxm/p/13626102.html