前言:
本文将简单的介绍JAVA并发中的线程。
操作系统的多任务(multitasking):计算机在同一刻运行多个程序的能力,即并发。并发执行的进程数目并不是由CPU数目制约的,操作系统将CPU时间片给每一个进程,给人并行处理的感觉。多线程程序在较低层次扩展了多任务的概念:一个程序可以同时处理多个任务。通常,每一个任务称为一个进程。
进程与线程的区别:本质的区别在于每一个进程拥有自己的一整套变量,而线程共享数据。共享数据会在同步时带来风险,然而共享变量使线程之间的通信比进程之间的通信更有效、更容易。与进程相比,线程更加“轻量级”,创建、撤销一个线程比启动新进程的开销要小得多。
单独的线程中执行一个任务的简单过程:
1)将任务代码移到实现了Runnable接口的类中:Runnable
接口十分简单,只需要实现一个run
方法
public interface Runnable{
void run();
}
2)由Runnable
创建一个Thread
对象
Thread thread = new Thread(runnable);
3)启动线程 thread.start();
不要调用Tread类或Runnable
对象的run方法。直接调用run
方法,只会执行一个线程中的任务,而不会启动新线程。应该调用Thread.run()
方法。这样将会创建一个新线程来执行run
方法。
线程终止:当线程的run方法执行方法体中最后一条语句时,并经由执行return语句返回时,或者出现了在方法中没有捕获的异常时,线程终止。在早期Java版本中,有一个stop方法可以被其他线程调用它终止线程,这方法已被弃用,不推荐使用。
现在没有强制停止线程的方法,但可以通过interrupt
(中断)方法发送请求终止线程。当线程调用这方法是,线程的中断状态将被置位,这是每一个线程都具有的boolean标志。每个线程都会不时的检查这个标志,以判断线程是否被请求中断。
想要知道当前线程是否被置位,首先应调用静态的Thread.currentThread
方法来获得当前线程,然后调用isInterrupt
方法:
while(!Thread.currentThread().isInterrupt() && more work to do){
do more work;
}
但是,当一个线程被阻塞,就无法检测中断状态。当阻塞和中断请求碰撞在一起时,会产生InterruptedException
。当在一个被阻塞的的线程(线程调用sleep或wait会被阻塞)上调用interrupt时,阻塞调用将会被InterruptedException
中断。
没有任何语言方面的需求要求一个被中断的线程应该终止。中断一个线程不过是引起它的注意。被中断的线程可以决定如何响应中断。某些重要的线程应该处理完异常后,继续执行,而不会理会中断。但更普遍的情况是,线程简单的将中断作为一个终止的请求。这种现成的run方法如下:
Runable r = () ->{
try{
...
while(!Thread.currentThread().isInterrupt() && more work to do){
do more work;
}
}catch(InterruptedException e){
//thread was interrupted during sleeo or wiat
}finally{
//cleanup,if required
}
//exiting thr run method terminates the thread
}
如果在每次工作迭代之后都调用sleep方法(或其他的可中断方法),inInterrupt
检测既没有必要也没有用处。如果在中断状态被置位是调用sleep方法,线程不会休眠。相反,它将会清除这一状态并抛出InterruptedException
异常。
相似的方法:
interrupted
和isInterrupt
interrupted
方法是一个静态方法,它检测当前的线程是否被中断,调用interrupted
方法会清除该线程的中断状态。
isInterrupt
方法是一个实例方法,可用来检测是否有线程被中断,调用这个方法不会改变中断状态。
s
void interrupt()
向线程发送中断请求。将线程中断状态设置为true。如果当前线程被sleep
或wait
调用阻塞,那么InterruptedException
异常被抛出
static boolean interrupted()
测试当前线程是否被中断,静态方法。调用这方法会产生另一作用,它将当前线程的中断状态重置为false。
boolean isInterrupt()
测试线程是否被终止,不会改变中断状态。
static Thread currentThread()
返回代表当前执行线程的Thread对象。
线程有六种状态:
通过调用getState
方法可确定一个线程的当前状态
新建状态
? 当new Thread一个新线程时,改线程还没有还是运行,意味这它的状态是new,当线程处于这一状态时,程序不会开始执行线程中的代码。
Thread thread = new Thread(runnable)
可运行线程
? 当调用线程的start
方法,线程处于runnable可运行状态。要注意,一个可运行的线程可能正在运行也可能没有运行,线程的运行取决于操作系统给线程提供运行的时间。系统会从处于可运行状态的线程队列中调度线程,为其提供CPU时间片。
? 我们将这一状态的线程称为可运行而不是运行。一旦一个线程开始运行,它不必始终保持运行。运行中的线程被中断,为的是让其他线程获得运行机会。
? 线程调度的细节依赖于操作系统提供的服务。现在所有的桌面以及服务器操作系统都使用抢占式调度。抢占式调度系统给每一个可运行线程一个时间片来执行程序。当时间片用完,操作系统剥夺该线程的运行权,并给另一个线程运行机会。在选择下一个线程时,操作系统还会考虑线程的优先级。
被阻塞和等待线程
? 当线程处于被阻塞或等待状态时,它不运行任何代码且消耗最少的资源。
java.util.concurrent
库中的锁),而该锁被其他线程持有,则该线程进入阻塞状态。只有当该锁被持有的线程释放时,所有请求该锁的线程变为非阻塞状态,并竞争该锁。Thread
,jion
方法,或者是等待java.util.concurrent
库中的Lock
或Condition
时,就会出现线程等待。被终止的线程
线程有如下两个原因之一而被终止:
因为run方法正常退出而自然死亡
因为一个没有捕获的异常终止了run方法而意外死亡
线程的属性包括:线程优先级,守护线程,线程组以及处理未捕获异常的处理器。
线程优先级
? 在Java中,每一个线程有一个优先级,默认情况加,一个线程继承它的父线程的优先级。
? 可用setPriority方法提高或降低任何一个线程的优先级。。可以将优先级设置在MIN_PRIORITY(1)与MAX_PRIORITY(10)之间的任何值。NORM_PRIORITY被定义为5。每当线程调度器有机会选择新线程时,它首先选择具有较高优先级的线程。但是,线程的优先级是高度依赖于操作系统的。当虚拟机依赖于宿主机平台的线程实现机制时,Java线程的优先级被映射到宿主机平台的优先级上。
? 在设置线程优先级时,要防止线程饿死。每当调度器决定运行一个新线程时,首先会在具有高优先级的线程中进行选择,尽管这样会使低优先级的线程完全饿死。
守护线程
通过调用:
t.setDaemon(true);
将线程设置为守护线程。
守护线程的唯一作用就是为其他线程提供服务。当只剩下守护线程时。虚拟机就会退出。
未捕获异常处理器
? 线程run方法不能抛出任何的受查异常,而受查异常又会导致线程终止,此时县城就死亡了。有有种办法,不需要任何catch子句来处理被传播的异常。在线程死亡之前,异常被传递到一个用于捕获异常的处理器。
? 捕获异常的处理器必须属于一个实现Thread.UncaughtExceptionHandler
接口的类,接口内只有一个方法。
? void uncaughtException(Thread t, Throwable e);
? 可以用setUncaughtExceptionHandler
方法为任何线程安装处理器。也可以用setDefauktUncaughtHandler
为所有线程安装一个默认的处理器。如果没有,默认的处理器为空。
原文:https://www.cnblogs.com/hbcolorful/p/13947206.html