创建线程
建议不要通过构建Thread子类对象,并调用start方法。应该从运行机制上减少需要并行运行的任务数量。如果有很多任务,要为每个任务创建一个独立的线程付出的代价太大,可以使用线程池来解决这个问题。(参考14.9)
java.lang.Thread
- Thread(Runnable target) 构造一个新线程用于调用给定target的run方法。
- void start() 启动此线程,将引发调用run()方法,这个方法会立即返回,并且新线程将并行运行。
- void run() 调用关联Runnable的run方法。
java.lang.Runnable
- void run() 必须覆盖这个方法,并在这个方法中提供所需要执行的任务指令。
中断线程
早期java使用stop()方法可以强制线程中止,现在已经被弃用;
interrupt() 方法可以用来请求中止线程。但是如果线程被阻塞,就无法检测中断状态。这是产生InterruptedException异常的地方,当在一个被阻塞的线程(调用sleep或wait)上调用interrupt方法时,阻塞调用将会被InterruptedException异常中断,这里指会进入catch代码块执行
(存在不能被中断的阻塞I/O调用,应该考虑选择可中断的调用。细节参考卷二 第一章和第三章)
java.lang.Thread
- void interrupt() 向线程发送中断请求,线程的
中断状态
将被设置为true.
如果目前线程被一个sleep调用阻塞,那么InterruptedException异常被抛出,此外中断状态将被清除
- static boolean interrupted() 测试正在执行这一方法的线程是否被中断,注意这是一个静态方法,调用会产生副作用,它将当前线程的
中断状态
重置为false.(线程的中断状态被清除
)- boolean isInterrupted() 测试线程是否终止,不像静态的中断方法,这一调用不改变线程的中断状态。
- static Thread currentThread() 返回代表当前执行线程的Thread对象。
- static void sleep(long millis) 休眠给定的毫秒数
void interrupt() 中断此线程。(谷歌翻译)
线程用一个变量来标志中断状态,private volatile Interruptible blocker;
除非当前线程正在中断自身(始终允许),否则将调用此线程的checkAccess方法,这可能导致抛出SecurityException。
如果在调用Object类的wait(),wait(long)或wait(long,int)方法或者join(),join(long),join(long,int)的方法中阻塞了这个线程,sleep(long)或sleep(long,int),这个类的方法,然后它的中断状态将被清除,它将收到InterruptedException。
如果此线程在可中断通道上的I / O操作中被阻塞,则通道将被关闭,线程的中断状态将被设置,并且线程将收到ClosedByInterruptException。
如果此线程在Selector中被阻塞,则线程的中断状态将被设置,并且它将立即从选择操作返回,可能具有非零值,就像调用选择器的唤醒方法一样。
如果以前的条件都不成立,则将设置该线程的中断状态。
中断不活动的线程不会产生任何影响。
public class TestRun implements Runnable {
private boolean flag = true;
@Override
public void run() {
try {
while (!Thread.currentThread().isInterrupted() && flag) {
// do more work
Thread.currentThread().sleep(1000);
}
}
catch (InterruptedException e) {
// thread was interrupted during sleep or wait
}
finally {
//cleanup,if required
}
//exiting the run method terminates the thread
}
void mySubTask() {
try {
Thread.currentThread().sleep(1000);
}
catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
}
void mySubTask2() throws InterruptedException {
Thread.currentThread().sleep(1000);
}
}
线程状态
- 新建 New
new Thread(r)/new MyThread() - 可运行 Runnable
thread.start()
(抢占式调度系统
;协作式调度系统中,一个线程只有在调用yield方法或者被阻塞或等待时,线程才会失去控制权
)
任何时刻,一个可运行的线程可能正在运行,也可能没有运行
- 被阻塞 Blocked
一个线程试图获取一个内部对象锁,而该锁被其它对象持有,则线程进入阻塞状态。
- 等待 Waiting/ 计时等待 Timed waiting
Thread.sleep
Object.wait
Thread.join
Lock.tryLock
Condition.await
- 被中止 Terminated
因为run方法正常退出而自然死亡
因为一个没有捕获的异常中止了run方法而意外死亡
stop方法已过时,不要在代码中使用
- 相关的API
java.lang.Thread
6.1
void join():等待中止指定的线程即等待指定的线程终止后再继续当前线程
6.2void join(long millis):等待指定的线程死亡,或者经过指定的毫秒数
6.3Thread.State getState():获取线程的状态
6.4void stop():停止线程,已过时
6.5void suspend:暂停线程执行,已过时
6.6void resume:调用suspend之后调用,已过时
线程属性
- 优先级
高优先级只代表线程优先获取时间片的可能性比较大,不是必然
- API
java.lang.Thread
2.1
void setPriority(int newPriority):设置优先级,必须在Thread.MIN_PRIORITY与Thread.MAX_PRIORITY之间,一般使用Thread.NORM_PRIORITY优先级。
2.2static int MIN_PRIORITY:线程最小优先级1.
2.3static int MAX_PRIORITY:线程最大优先级10.
2.4static int NORM_PRIORITY:线程默认优先级5.
2.5static void yield():导致当前执行线程处于让步状态,如果有其他可运行的线程具有至少与此线程同样高的优先级,那么这些线程接下来会被调度。注意,这是一个静态方法。
3.守护线程/API
3.守护线程优先级很低,当同一应用程序中没有其他线程在运行的时候,守护线程才运行。当守护线程是程序中唯一运行的线程时,守护线程执行结束后,JVM也就结束了这个程序。
3.2守护线程的作用:通常作为同一程序中普通线程的服务提供者,它们通常是无限循环的,以等待服务请求或者执行线程的任务。此外我们不太可能知道守护线程什么时候能够获取CPU时钟,并且没有其它线程运行的时候,守护线程随时可能结束。一个典型的守护线程是Java的垃圾回收器。
java.lang.Thread
3.3
void setDaemon(boolean isDaemon):标识该线程为守护线程或用户线程。这一方法必须在线程启动之前调用
4未捕获异常处理器
4.1未捕获异常处理器介绍
线程的run方法不能抛出任何被检测的异常,但是,不被检测的异常会导致线程终止。在这种情况下,线程就死亡了。就作线程死亡之前,异
常被传递到一个用于未捕获异常的处理器。
该处理器必须属于一个实现Thread.UncaughtExceptionHandler
接口的类。
这个接口只有一个方法。
void uncauqhtException(Thread t, Throwable e)
可以用 setUncaughtExceptionHandler
方法为任何线程安装一个处理器。也可以用 Thread类的静态方法setDefaultUncaughtExceptionHandlcr
为所有线程安装一个默认的处理器。如果不安装默认的处理器,默认的处理器为空。但是,如果没有设置UncaughtExceptionHandler
,那么默认将会把异常栈信息输出到System.err
,此时的处理器就足该线程的ThreadGroup对象
。
线程组是一个可以统一管理的线程集合。默认情况下,创建的所有线程属于相同的线程组,但是,也可能会建立其他的组。现在引入了更好的特性用于线程集合的操作,所以建议不要在自己的程序中使用线程组。
ThreadGroup 类实现 Thread.UncaughtException 接口
。它的uncaughtException方法如下:
/**
* Called by the Java Virtual Machine when a thread in this
* thread group stops because of an uncaught exception, and the thread
* does not have a specific {@link Thread.UncaughtExceptionHandler}
* installed.
* <p>
* The <code>uncaughtException</code> method of
* <code>ThreadGroup</code> does the following:
* <ul>
* <li>If this thread group has a parent thread group, the
* <code>uncaughtException</code> method of that parent is called
* with the same two arguments.
* <li>Otherwise, this method checks to see if there is a
* {@linkplain Thread#getDefaultUncaughtExceptionHandler default
* uncaught exception handler} installed, and if so, its
* <code>uncaughtException</code> method is called with the same
* two arguments.
* <li>Otherwise, this method determines if the <code>Throwable</code>
* argument is an instance of {@link ThreadDeath}. If so, nothing
* special is done. Otherwise, a message containing the
* thread's name, as returned from the thread's {@link
* Thread#getName getName} method, and a stack backtrace,
* using the <code>Throwable</code>'s {@link
* Throwable#printStackTrace printStackTrace} method, is
* printed to the {@linkplain System#err standard error stream}.
* </ul>
* <p>
* Applications can override this method in subclasses of
* <code>ThreadGroup</code> to provide alternative handling of
* uncaught exceptions.
*
* @param t the thread that is about to exit.
* @param e the uncaught exception.
* @since JDK1.0
*/
public void uncaughtException(Thread t, Throwable e) {
if (parent != null) {
parent.uncaughtException(t, e);
} else {
Thread.UncaughtExceptionHandler ueh =
Thread.getDefaultUncaughtExceptionHandler();
if (ueh != null) {
ueh.uncaughtException(t, e);
} else if (!(e instanceof ThreadDeath)) {
System.err.print("Exception in thread \""
+ t.getName() + "\" ");
e.printStackTrace(System.err);
}
}
}
4.2相关API
java.lang.Thread
4.2.1 public static void setDefaultUncaughtExceptionHandler(Thread.UncaughtExceptionHandler)
4.2.2 public static Thread.UncaughtExceptionHandler getDefaultUncaughtExceptionHandler()
4.3.3 public void setUncaughtExceptionHandler(Thread.UncaughtExceptionHandler eh)
4.4.4 public Thread.UncaughtExceptionHandler getUncaughtExceptionHandler()
java.lang.Thread.UncaughtExceptionHandler
4.2.5 void uncaughtException(Thread t,Throwable e)当给定线程因给定的未捕获异常而终止时,调用该方法。 Java 虚拟机将忽略该方法抛出的任何异常。
java.lang.ThreadGroup
4.2.6 public void uncaughtException(Thread t,Throwable e)当此线程组中的线程因为一个未捕获的异常而停止,并且线程没有安装特定 Thread.UncaughtExceptionHandler 时,由 Java Virtual Machine 调用此方法。
ThreadGroup 的 uncaughtException 方法执行以下操作:
1.如果此线程组有一个父线程组,那么调用此父线程组的 uncaughtException 方法时带有两个相同的参数。
2.否则,此方法将查看是否安装了默认的未捕获异常处理程序,如果是,则在调用其 uncaughtException 方法时带有两个相同的参数。
3.否则,此方法将确认 Throwable 参数是否为一个 ThreadDeath 实例。如果是,则不会做任何特殊的操作。否则,在从线程的 getName 方法返回时,会使用 Throwable 的 printStackTrace 方法,将包含线程名称的消息和堆栈跟踪信息输出到标准错误流。
应用程序可以重写 ThreadGroup 的子类中的方法,以提供处理未捕获异常的替代办法。