此处只讨论,Thread中的所有public方法。
其中,可以分为以下两种:
静态static方法在调用时,只能对当前的线程进行操作,具体用法都是:Thread.方法名()
非静态方法在调用时,不仅可以通过 Thread.currentThread().方法名() 来对当前线程进行操作;还可以直接通过Thread类的实例进行调用。
例如:
Thread t1=new Thread(sleepDemo);
t1.start();
t1.方法名();
Thread.sleep()的用法:
package com.thread;
/**
* @Description:
*/
public class SleepDemo implements Runnable{
@Override
public void run() {
while (true){
try {
Thread.sleep(1000);
System.out.println("当前线程:"+Thread.currentThread().getName()+"休眠1秒");
Thread.currentThread().sleep(1000);
System.out.println("当前线程:"+Thread.currentThread().getName()+"休眠1秒");
} catch (InterruptedException e) {
System.out.println("当前线程:"+Thread.currentThread().getName()+"休眠时被中断");
System.out.println("当前中断状态为:"+Thread.currentThread().isInterrupted());
break;
}
}
}
public static void main(String[] args) throws InterruptedException {
SleepDemo sleepDemo=new SleepDemo();
Thread t1=new Thread(sleepDemo);
t1.setName("sleepDemo");
t1.start();
System.out.println("当前线程:"+Thread.currentThread().getName());
t1.sleep(50);
System.out.println("注意:t1.sleep仍然是main线程进入休眠了");
Thread.sleep(2000);
t1.interrupt();
}
}
运行结果:
当前线程:main 注意:t1.sleep仍然是main线程进入休眠了 当前线程:sleepDemo休眠1秒 当前线程:sleepDemo休眠1秒 当前线程:sleepDemo休眠时被中断 当前中断状态为:false
总结:
Thread.sleep(1000); 与 Thread.currentThread().sleep(1000); 等价,都是在何处调用,就会使得当前的线程进入休眠状态。因此,t1.sleep(50); 同样是main线程休眠了50毫秒。
sleep()支持中断,因此当检测到中断信号时,会抛出InterruptedException 异常,从而告知程序该线程应当对中断进行某些响应操作。通过isInterrupted()可以发现:在抛出异常的时候,还让异常状态重新置为了false。
需要注意:由于不允许不同的线程之间的异常溢出,因此在run方法中就必须对此处抛出的InterruptedException异常进行处理,因此上述示例代码,直接对异常进行了捕捉。若是在其他的普通方法中,除非是线程需要退出,否则都不应当直接将异常生吞。此时可以选择:1.不捕捉 InterruptedException,将它传播给调用者;2.捕捉InterruptedException执行必要的清理操作,重新向上抛出InterruptedException异常;3.捕捉 InterruptedException 后重新恢复中断状态。
sleep方法不会释放锁。如果当前线程持有对某个对象的锁,则即使调用了sleep方法,其他线程也无法获得这个对象的锁。
Thread.currentThread()的用法:
Thread.currentThread()返回对当前正在执行的线程对象的引用。换句话说, Thread.currentThread() 返回的是一个实例。这个实例是当前Thread 的引用。
Thread.yield()的用法:
yield方法的作用是对线程调度器的一种建议:当前线程已执行完成重要的部分,现在时切换给其他线程执行一段时间的好时机。不过不能指定暂停的时间,并且也不能保证当前线程马上停止。因为有可能在下一个时间片当前线程再次被选中然后继续执行。
yield只能使同优先级或更高优先级的线程有执行的机会,但是不能保证。所有对于很严格的控制时,不能依赖于yield().
调用实例:
在需要执行让步操作的线程中直接调用(如:run方法中):
Thread.yield();
需要注意:t1.yield();与Thread.yield(); 等价 都是将当前线程抢占权让出。t1.yield(); 无法使得当前线程控制其他线程 t1 交出抢占权。
yield方法不会释放锁。如果当前线程持有对某个对象的锁,则即使调用了yield方法,其他线程也无法获得这个对象的锁。
Thread.interrupted()的用法:
返回中断状态值,并重置线程的中断状态为false.
调用实例:
获取当前线程的中断状态(适用于非阻塞方法或不支持响应中断的阻塞方法):
while (!Thread.interrupted()){
System.out.println("aaaaa");
}
需要注意:t1.interrupted();与Thread.interrupted(); 等价 都是获得当前线程的中断状态。t1.interrupted(); 无法获得其他线程 t1 的中断状态。
start()的用法:
源码:
public synchronized void start() {
// 线程不能重复start,否则会抛出IllegalThreadStateException
if (threadStatus != 0)
throw new IllegalThreadStateException();
//添加到线程组,启动数加1,启动失败数减1
group.add(this);
boolean started = false;
try {
start0();//启动线程的native方法
started = true;//启动成功
} finally {
try {
if (!started) {//若启动失败
group.threadStartFailed(this);//从线程组移除,启动失败数加1
}
} catch (Throwable ignore) {
/* do nothing. If start0 threw a Throwable then
it will be passed up the call stack */
}
}
}
一个线程启动另一个线程执行的唯一方法。并且同一个线程不能多次start,否则会抛出IllegalThreadStateException异常。
调用实例:
Thread t1=new Thread(sleepDemo);
t1.start();
run()的用法:
源码:
@Override //实现了Runnable的run方法
public void run() {
if (target != null) {
target.run();
}
}
target为Runnable成员变量实例,可以发现若直接执行run方法,并没有执行启动另一个线程的相关操作,因此执行的仍然是执行run方法的那个线程而已,等同于执行了另一个实例对象中方法名为run的普通方法。
需要注意:target对象的初始化时在Thread的构造方法中完成的。
Thread的构造函数:
public Thread() {//无参构造器
init(null, null, "Thread-" + nextThreadNum(), 0);//初始化线程名称为'Thread-'加当前线程数,线程栈大小为0
}
//Runnable target 实现了Runnable接口的类的实例
public Thread(Runnable target) {
init(null, target, "Thread-" + nextThreadNum(), 0);//初始化线程名称为'Thread-'加当前线程数,线程栈大小为0
}
Thread(Runnable target, AccessControlContext acc) {
init(null, target, "Thread-" + nextThreadNum(), 0, acc, false);
}
//ThreadGroup group 当前建立的线程所属的线程组.如果不指定线程组,所有的线程都被加到一个默认的线程组中
//Runnable target 实现了Runnable接口的类的实例
public Thread(ThreadGroup group, Runnable target) {
init(group, target, "Thread-" + nextThreadNum(), 0);//初始化线程名称为'Thread-'加当前线程数,线程栈大小为0
}
//String name 线程的名字
public Thread(String name) {
init(null, null, name, 0);//初始化线程栈大小为0
}
//ThreadGroup group 当前建立的线程所属的线程组.如果不指定线程组,所有的线程都被加到一个默认的线程组中
//String name 线程的名字
public Thread(ThreadGroup group, String name) {
init(group, null, name, 0);//初始化线程栈大小为0
}
//Runnable target 实现了Runnable接口的类的实例
//String name 线程的名字
public Thread(Runnable target, String name) {
init(null, target, name, 0);//初始化线程栈大小为0
}
//ThreadGroup group 当前建立的线程所属的线程组.如果不指定线程组,所有的线程都被加到一个默认的线程组中
//Runnable target 实现了Runnable接口的类的实例
//String name 线程的名字
public Thread(ThreadGroup group, Runnable target, String name) {
init(group, target, name, 0);//初始化线程栈大小为0
}
//ThreadGroup group 当前建立的线程所属的线程组.如果不指定线程组,所有的线程都被加到一个默认的线程组中
//Runnable target 实现了Runnable接口的类的实例
//String name 线程的名字
//long stackSize 线程栈的大小
public Thread(ThreadGroup group, Runnable target, String name, long stackSize) {
init(group, target, name, stackSize);
}
interrupt()的用法:
不意味着立即停止目标线程的执行,而是传递了中断的消息请求。设置线程的中断状态为true,其初始状态为false。
中断的含义:提前结束或取消目标线程的执行。
对于支持响应中断的阻塞方法(sleep、join、wait等),当检测到中断请求时,将抛出异常。通过对异常的处理,可以很好地对中断做出响应。
对于不支持响应中断的阻塞方法,可能会一直无法检测到中断请求,直至阻塞方法执行完毕。
对于非阻塞方法,可以通过轮询查看中断状态值,对中断做出响应。
调用实例:
中断当前线程执行(任何方法均可这样使用):
Thread.currentThread().interrupt();
中断其他线程的执行(在创建其他线程的方法中执行中断其他线程的操作):
Thread t1=new Thread(sleepDemo);
t1.start();
t1.interrupt();
isInterrupted()的用法:
判断线程是否已经中断,不对线程中断状态作任何改变。
如果该线程已经中断,则返回 true
;否则返回 false
。
需要注意:如果存在可响应中断的阻塞方法,当抛出异常的同时会将中断状态重新置为false。
调用实例:
判断当前线程是否中断:
Thread.currentThread().isInterrupted();
判断其他线程是否中断:
Thread t1=new Thread(sleepDemo);
t1.start();
t1.interrupt();
System.out.println("t1中断状态:"+t1.isInterrupted());
join()的用法:
当前线程等待另一线程的执行。如果当前线程的执行过程中检测到中断信号,则抛出异常并将中断状态重置。
join() 等待该线程终止 join(long millis) 等待该线程终止的时间最长为 millis 毫秒。超时为0 则意味着要一直等下去 join(long millis,int nanos) 等待该线程终止的时间最长为 millis 毫秒 + nanos 纳秒
作用是父线程等待子线程执行完成后再执行。换句话说就是将异步执行的两个线程合并为一个同步执行的线程。
需要注意:正确的使用,只有当前线程等待另一线程执行。有参数,则只等待指定的时间;无参数,则等待另一线程执行完成方可继续当前线程的执行。join方法是一个支持中断响应的阻塞方法,因此当前线程在等待过程中, 只有有线程中断了当前线程,则当前线程会抛出InterruptedException异常,并将当前线程的中断状态重置。
调用实例:
(禁止这样使用)当前线程等待当前线程的执行,当前线程将一直挂起,无法继续执行,直至接受到中断信号才能做出响应:
Thread.currentThread().join();
当前线程等待其他线程的执行:
Thread t1=new Thread(sleepDemo);
t1.start();
t1.join(2000); //当前线程等待线程 t1 执行2秒
t1.join(); //当前线程等待线程 t1 执行完毕
isAlive()的用法:
测试线程是否处于活动状态。如果线程已经启动且尚未终止,则为活动状态。如果该线程处于活动状态,则返回 true
;否则返回 false
。
调用实例:
测试当前线程的活动状态(无意义,返回结果一定为true):
Thread.currentThread().isAlive();
测试其他线程的活动状态:
Thread t1=new Thread(sleepDemo);
t1.start();
Thread.sleep(2000);
t1.isAlive();
stop()的用法:
强制线程停止执行。(不推荐使用!)
调用实例:
强制停止当前线程执行(任何方法均可这样使用):
Thread.currentThread().stop();
强制停止其他线程的执行(在创建其他线程的方法中执行停止其他线程的操作):
Thread t1=new Thread(sleepDemo);
t1.start();
... ...
t1.stop();
suspend()的用法:
暂停线程,但并不释放资源。(不推荐使用)
该方法已经遭到反对,因为它具有固有的死锁倾向。
如果目标线程挂起时在保护关键系统资源的监视器上保持有锁,则在目标线程重新开始以前任何线程都不能访问该资源。
如果重新开始目标线程的线程想在调用 resume
之前锁定该监视器,则会发生死锁。这类死锁通常会证明自己是“冻结”的进程。
调用实例:
暂停当前线程执行(任何方法均可这样使用):
Thread.currentThread().suspend();
暂停其他线程的执行(在创建其他线程的方法中执行暂停其他线程的操作):
Thread t1=new Thread(sleepDemo);
t1.start();
... ...
t1.suspend();
resume()的用法:
只与suspend()一起使用,用于重新开始挂起的进程。(不推荐使用)
如果线程处于活动状态但被挂起,则它会在执行过程中重新开始并允许继续活动。
只与suspend()一起使用,但 suspend() 已经遭到反对。
调用实例:
恢复当前线程的执行(任何方法均可这样使用):
Thread.currentThread().suspend();
Thread.currentThread().resume();
恢复其他线程的执行(在创建其他线程的方法中执行恢复其他线程的操作):
Thread t1=new Thread(sleepDemo);
t1.start();
... ...
t1.suspend();
t1.resume();
setPriority()的用法:
设置线程的优先级。(优先级越高的线程越可能先执行)
源码:
public final void setPriority(int newPriority) {
ThreadGroup g;
checkAccess();
if (newPriority > MAX_PRIORITY || newPriority < MIN_PRIORITY) {
throw new IllegalArgumentException();
}
if((g = getThreadGroup()) != null) {
if (newPriority > g.getMaxPriority()) {
newPriority = g.getMaxPriority();
}
setPriority0(priority = newPriority);
}
}
虽然拥有MIN_PRIORITY 到 MAX_PRIORITY 的之间的10个优先级,但是它与操作系统之间的映射关系不是太好。
一般情况下,最好只使用以下三个级别作为优先级级别:
MIN_PRIORITY = 1;
NORM_PRIORITY = 5;
MAX_PRIORITY = 10;
调用实例:
设置当前线程的优先级:
Thread.currentThread().setPriority(Thread.MIN_PRIORITY);
设置其他线程的优先级:
Thread t1=new Thread(sleepDemo);
t1.setPriority(Thread.MIN_PRIORITY);
t1.start();
getPriority()的用法:
获得线程的优先级。
调用实例:
获得当前线程的优先级:
Thread.currentThread().getPriority();
获得其他线程的优先级:
Thread t1=new Thread(sleepDemo);
t1.start();
t1.getPriority();
setName()的用法:
设置线程的名字。
源码:
public final synchronized void setName(String name) {
checkAccess();
if (name == null) {
throw new NullPointerException("name cannot be null");
}
this.name = name;
if (threadStatus != 0) {
setNativeName(name);
}
}
注意:在调用start方法前后都可以使用setName设置线程名,但在调用start方法后使用setName修改线程名,会产生不确定性,也就是说可能在run方法执行完后才会执行setName。如果在run方法中要使用线程名,就会出现虽然调用了setName方法,但线程名却未修改的现象。
调用实例:
设置当前线程的名字:
Thread.currentThread().setName("线程名");
设置其他线程的名字:
Thread t1=new Thread(sleepDemo);
t1.setName("线程名");
t1.start();
getName()的用法:
获得线程名称。
调用实例:
获得当前线程的名字:
Thread.currentThread().getName("线程名");
获得其他线程的名字:
Thread t1=new Thread(sleepDemo);
t1.start();
String name=t1.getName("线程名");
System.out.println("线程名:"+name);
setDaemon(boolean on) 的用法:
将该线程标记为守护线程或用户线程。
on为true:标记为守护(后台)线程;
on为false:标记为用户线程;
默认为false,该方法必须在启动线程前调用,才能设置为后台线程。
当所有的非后台线程结束时,程序就终止了,同时会杀死进程中所有的后台线程。
执行main的线程就是一个非后台线程。如果使用一个后台程序创建线程,则它创建的任何线程都将自动设置为后台线程。
因此如果在main方法中启动一个后台线程,则往往会出现main执行完毕,程序会立即退出,而不会等待后台线程执行完毕。
调用实例:
Thread t1=new Thread(sleepDemo);
t1.setDaemon(true);//设置为后台线程。
t1.start();
isDaemon()的用法:
判断该线程是否为守护线程。如果该线程是守护线程,则返回 true;否则返回 false。
调用实例:
判断当前线程是否为守护线程:
Thread.currentThread().isDaemon();
判断其他线程是否为守护线程:
Thread t1=new Thread(sleepDemo);
t1.setDaemon(true);//设置为后台线程
t1.start();
t1.isDaemon();//检查t1是否为守护线程。
activeCount()的用法:
返回当前线程的线程组中活动线程的数目。
getThreadGroup()的用法:
返回该线程所属的线程组ThreadGroup,如果该线程已经终止(停止运行),该方法则返回 null。