多线程的创建、停止
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
作者:诗和远方
本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利.