《java 核心技术》这本书真的不错,知识点很全面,翻译质量也还不错,本系列博文是对该书中并发章节的一个总结。html
官方解释:线程是操做系统可以进行运算调度的最小单位,包含于进程之中,是进程中的实际运做单位。也就是说线程是代码运行的载体,咱们所编写的代码都是在线程上跑的,以一个最简单的 hellowWorld 为例:java
public class Main { public static void main(String[] args) { System.out.println("Hello World!"); System.out.println("当前线程名为:"+Thread.currentThread().getName()); System.out.println("当前线程id为:"+Thread.currentThread().getId()); } }
<!-- more -->git
结果为:github
Hello World! 当前线程名为:main 当前线程id为:1
在程序运行时默认会建立一个主线程来执行代码,线程名为:main,线程 id 为 1多线程
顾名思义就是多个线程同时运行,提升程序执行速度。单个线程一次只能作一件事,想要提升执行效率有两种途径:并发
建立线程有两种方法dom
不推荐本方式来建立线程,缘由显而易见:java 不支持多继承,若是继承了 Thread 类就不能再继承其余类了。异步
使用继承方式建立线程代码以下:ide
public class CustomThreadExtendThread extends Thread{ @Override public void run() { String threadName = Thread.currentThread().getName(); long threadId = Thread.currentThread().getId(); System.out.println("建立线程名为:"+threadName+",id为:"+threadId); } public static void main(String[] args){ Thread thread1 = new CustomThreadExtendThread(); Thread thread2 = new CustomThreadExtendThread(); thread1.start(); thread2.start(); } }
实现接口来建立线程是目前推荐的一种方式,缘由也很简单:一个类能够实现多个接口。实现 Runnable 接口并不影响实现类再去实现其余接口。学习
使用实现接口方式建立线程代码以下:
public class CustomThreadImplementInterface implements Runnable { @Override public void run() { Thread.currentThread().setName(((Double) Math.random()).toString()); String threadName = Thread.currentThread().getName(); long threadId = Thread.currentThread().getId(); System.out.println("建立线程名为:" + threadName + ",id为:" + threadId); } public static void main(String[] args) { Thread thread1 = new Thread(new CustomThreadImplementInterface()); Thread thread2 = new Thread(new CustomThreadExtendThread()); thread1.start(); thread2.start(); //使用lambda表达式,让建立线程更简单 new Thread(() -> { System.out.println("建立了一个新线程"); }).start(); } }
经过查看 Thread 源码能够看到 Thread 类也是 Runnable 接口的一个实现类。
PS:后续代码所有使用 runnable 建立线程
上面只是演示了线程的建立,如今来详细了解线程的状态。在 java 规范中,线程能够有如下 6 种状态:
当使用 new 操做符建立一个线程时,如 new Thread(r),线程还未开始运行,就属于新建立状态。
一旦调用 Thread 类的 start 方法,线程就处于可运行状态。
为何要叫可运行状态?
由于 Java 的规范中并无将正在 CPU 上运行定义为一个单独的状态。所以处于可运行状态的线程可能正在运行,也可能没有运行,取决于 CPU 的调度策略。
当线程处于阻塞或等待状态时,不运行任何代码且消耗最少的资源。直到从新运行。有以下几种途径让线程进入阻塞或等待状态:
线程可由如下两种办法进入终止状态:
注意: 调用线程的 stop 方法也能够终止线程,可是这个方法已经被弃用,最好不要使用。
线程有各类属性:优先级,守护线程,线程组以及处理未捕获异常处理器。
java 中,每一个线程都有一个优先级。默认状况下,线程继承父线程优先级。也能够调用setPriority
方法指定优先级。优先级范围:1(MIN_PRIORITY)-10(MAX_PRIORITY).NORM_PRIORITY 为 5,这些常量定义在 Thread 类中.
注意: 线程优先级时高度依赖于系统的,所以当 java 线程优先级映射到宿主机平台的优先级时,优先级个数可能会变少或者变成 0.好比,Windows 中有 7 个优先级,java 线程映射时部分优先级将会映射到相同的操做系统优先级上。Oracle 为 Linux 编写的 java 虚拟机中,忽略了线程的优先级,全部 java 线程都有相同的优先级。不要编写依赖优先级的代码。
经过调用Thread.setDaemon(true)
将一个线程转换为守护线程。守护线程惟一的用户是为其余线程提供服务,好比计时线程,定时发送计时信号给其余线程。所以当虚拟机中只有守护线程时,虚拟机就会关闭退出。不要在守护线程中访问任何资源,处理任何业务逻辑
线程的 run 方法不能抛出任何受查异常,非受查异常会致使线程终止,除了 try/catch 捕获异常外,还能够经过未捕获异常处理器来处理异常。异常处理器须要实现Thread.UncaughtExceptionHandler
接口。
可使用线程示例的setUncaughtExceptionHandler()
方法为某个线程设置处理器,也可以使用Thread.setDefaultUncaughtExceptionHandler()
为全部线程设置默认处理器,代码以下:
public class CustomExceptionHandler implements Thread.UncaughtExceptionHandler { @Override public void uncaughtException(Thread t, Throwable e) { System.out.println("捕获到线程"+t.getName()+",异常:" + e.getMessage()); e.printStackTrace(); } public static void main(String[] args) { Thread.setDefaultUncaughtExceptionHandler(new CustomExceptionHandler()); new Thread(() -> { throw new RuntimeException("test"); }).start(); } }
若是不设置默认处理器且不为独立的线程设置处理器,那么该线程的处理器就为该线程的线程组对象--ThreadGroup(由于线程组对象实现了Thread.UncaughtExceptionHandler
接口)。
本篇所用所有代码:github
本篇原创发布于:https://www.tapme.top/blog/detail/2019-04-08-20-52
原文出处:https://www.cnblogs.com/wuyoucao/p/11100889.html