方法小结:
方法 | 作用 |
---|---|
join() | 执行该方法的线程进入阻塞状态,直到调用该方法的线程结束后再由阻塞转为就绪状态。 |
interrupt() | 结束线程在调用Object类的wait方法或该类的join方法、sleep方法过程中的阻塞状态,并在调用wait、join和sleep方法处产生InterruptedException异常。 |
currentThread() | 返回当前正在执行的线程对象。 |
isAlive | 判定该线程是否处于就绪、运行或阻塞状态,如果是则返回true,否则返回false。 |
setDaemon | 用于将一个尚未调用线程start方法的线程设置为守护线程。 |
start() | 使该线程开始启动,Java 虚拟机负责调用该线程的 run() 方法。多次启动一个线程是非法的。 |
sleep(long millis) | Thread类静态方法,线程进入阻塞状态,在指定时间(单位为毫秒)到达之后进入就绪状态(Runnable),而非立即进入执行状态。 |
yield() | 静态方法,当前线程放弃占用CPU资源,回到就绪状态,使其他优先级不低于此线程的线程有机会被执行。 |
setPriority(int newPriority) | 设置当前线程的优先级,线程优先级越高,线程获得执行的次数越多(具体与run方法消耗多少内存有关),Java线程的优先级用整数表示,取值范围是1~10。 |
getPriority() | 获得当前线程的优先级。 |
一、join方法:执行该方法的线程进入阻塞状态,直到调用该方法的线程结束后再由阻塞转为就绪状态。
例如:
import java.util.Date;
public class Test {
public static void main(String[] args) {
TimeThread timeThread = new TimeThread();
CountThread countThread = new CountThread(timeThread);
timeThread.start(); //线程对象在调用join方法前必须先调用start方法,否则该线程永远不会进入执行状态。
countThread.start();
}
}
//时间线程
class TimeThread extends Thread {
@Override
public void run() {
for (int i = 0; i < 3; i++) {
System.out.println("时间线程:" + new Date());
try {
sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
//计数线程
class CountThread extends Thread {
TimeThread timeThread;
public CountThread(TimeThread timeThread) {
this.timeThread = timeThread;
}
@Override
public void run() {
for (int i = 0; i < 3; i++) {
if (i == 1) {
try {
timeThread.join(); //循环到i=1时,CountThread进入阻塞,直到timeThread运行完才继续运行。
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println("计数线程:" + i);
}
}
}
输出:
分析:计数线程在第二次循环时执行了join方法,进入阻塞状态。此时运行调用join方法的时间线程。等待时间线程运行完毕,计数线程开始运行。
二、interrupt方法:结束线程在调用Object类的wait方法或该类的join方法、sleep方法过程中的阻塞状态,并在调用wait、join和sleep方法处产生InterruptedException异常。
例如:
import java.util.Date;
public class Test {
public static void main(String[] args) {
TimeThread timeThread = new TimeThread();
timeThread.start();
try {
Thread.sleep(1000); //main线程在这里阻塞1s。
} catch (InterruptedException e) {
e.printStackTrace();
}
timeThread.interrupt(); //结束了时间线程的阻塞状态。
}
}
class TimeThread extends Thread {
@Override
public void run() {
System.out.println(new Date());
try {
sleep(30000); //阻塞30s再继续进行。
} catch (InterruptedException e) {
System.out.println("捕获了InterruptedException异常。");
}
System.out.println(new Date());
}
}
输出:
分析:因为main线程在进行1s的阻塞后开始执行timeThread.interrupt();代码,此时时间线程的阻塞状态小时,本该30s后输出的数据在1s后输出。
三、currentThread方法:返回当前正在执行的线程对象。
例如:
public class Test {
public static void main(String[] args) {
TimeThread timeThread = new TimeThread();
System.out.println("########"+timeThread); //作为对比,证明时间线程执行生成的thread的确是时间线程的对象。
timeThread.start(); //此时timeThread的run方法是时间线程执行的。即thread是时间线程的对象。
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
timeThread.run(); //直接调用时,timeThread的run方法是main线程执行的。即thread是main线程的对象。
}
}
class TimeThread extends Thread{
@Override
public void run() {
Thread thread = Thread.currentThread();
System.out.println("@@@@@@@@"+thread);//输出线程名字。
}
}
输出:
分析:因为有1s阻塞,所以第二个是调用start()进入时间线程得到的,第三个是main线程直接调用run()得到的。很明显main线程直接调用run方法并没有进入时间线程,因此第三个thread是main线程对象。
四、isAlive方法:判定该线程是否处于就绪、运行或阻塞状态,如果是则返回true,否则返回false。
例如:
public class Test {
public static void main(String[] args) {
Thread thread = Thread.currentThread();
new PrintThread(thread).start();
System.out.println("main线程状态:"+thread.isAlive()); //能执行到此代码main线程一定存在,一定是true。
}
}
class PrintThread extends Thread{
private Thread thread;
public PrintThread(Thread thread){
this.thread = thread;
}
@Override
public void run() {
try {
sleep(1000); //阻塞1s,则main线程会在这1s内结束。
} catch (InterruptedException e) {
e.printStackTrace();
}
System.err.println("main线程状态:"+thread.isAlive()); //因为PrintThread有阻塞,此时main线程已经结束,返回false.
}
}
输出:
注:线程A执行“已死”线程B所调用的jion方法,则线程A不会阻塞,因为线程B已经结束了。
五、setDaemon方法:用于将一个尚未调用线程start方法的线程设置为守护线程。
守护线程特点:线程对象调用start之前调用setDaemon并且设置为true,则该线程为守护线程,随着进程中最后一个非守护线程的结束而结束。即最后一个非守护线程的结束意味着进程结束。
例如:
public class Test {
public static void main(String[] args) {
Thread mainThread = Thread.currentThread(); //mainThread为主线程对象。
TimeThread timeThread = new TimeThread(mainThread); //非守护线程。
timeThread.start();
CountThread countThread = new CountThread();
countThread.setDaemon(true); //设置countThread为守护线程。
countThread.start();
boolean isAlive = mainThread.isAlive();
System.out.println("主线程状态,主线程main方法监测点:"+isAlive); //观察主线程是否结束。能执行这行代码肯定没有结束。
}
}
class TimeThread extends Thread{ //非守护线程。
private Thread mainThread;
public TimeThread(Thread mainThread){
this.mainThread = mainThread;
}
@Override
public void run() {
for (int i=1; i<=2 ;++i) {
boolean isAlive = mainThread.isAlive();
System.out.println("主线程状态,时间线程run方法监测点:"+isAlive); //观察此时主线程是否结束。
System.out.println("时间线程:"+new java.util.Date()); //输出时间。
try {
Thread.sleep(1000); //阻塞1s。
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
class CountThread extends Thread{ //守护线程,会随着最后一个非守护线程的结束而结束。
@Override
public void run() {
for (int i = 0; ;i++) {
System.out.println("计数器线程:"+i);
try {
Thread.sleep(500); //阻塞0.5s。
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
输出:
分析:在执行第二次时间线程前,主线程已经关闭。最后一个非守护线程:时间线程结束后,计数线程关闭。虽然计数线程的内容是无限循环,但是也会随着最后一个非守护线程的关闭而关闭。
注:进程中所启动的其他非守护线程不会随着某一个非守护线程的结束而结束。