本篇文章將介紹Thread類相關方法,以及一些重要概念及應用。JDK提供了直觀觀察線程狀態的工具,在學習線程的過程中,可以使用
jconsole
命令打開Java監視和管理控制檯觀察線程運行狀態。
1. setDaemon()
守護線程
: 當子線程被設置爲守護線程時,父線程一旦進入DEAD狀態,守護線程也立即進入DEAD狀態。示例:
package com.juc;
/**
* 守護線程: 當被設置爲父線程的守護線程時,父線程一旦銷燬,子線程也立即銷燬。
* 1. setDaemon(boolean on)必須在線程變成Runnable狀態前執行
* 2. 爲維持長連接,需要心跳包,可以將心跳包設置爲守護線程,主線程一旦銷燬,即不用再發送心跳包維持狀態
*/
public class ThreadDaemon {
public static void main(String[] args) {
long interval = 2_000L;
Thread daemonThread = new Thread(() -> {
Thread innerDaemonThread = new Thread(() -> {
while (true) {
try {
Thread.sleep(interval);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + " is alive");
}
}, "innerDaemonThread");
innerDaemonThread.setDaemon(true);
innerDaemonThread.start();
while (true) {
try {
Thread.sleep(interval);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + " is alive");
}
}, "daemonThread");
daemonThread.setDaemon(true);
daemonThread.start();
try {
Thread.sleep(4_000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + " thread is dead");
}
}
2. join()
當線程對象使用join()方法後,當前線程所在的父線程將處於BLOCKED狀態直到當前線程任務執行完畢。示例:
package com.juc;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
import java.util.stream.IntStream;
/**
* join() 子線程在join()時,父線程會進入blocked狀態,直到子線程完成任務,父線程恢復正常
*
* Thread.currentThread().join() main會等待main,死循環
*/
public class ThreadJoin {
public static void main(String[] args) {
List<Thread> threadList = new ArrayList<>();
for (int i = 1; i < 4; i++) {
threadList.add(new ChildThread("childThread" + i));
}
threadList.forEach(
thread -> {
thread.start();
try {
thread.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
);
System.out.println("All done.");
}
}
class ChildThread extends Thread {
private String threadName;
public ChildThread(String threadName) {
this.threadName = threadName;
}
@Override
public void run() {
IntStream.range(1, 10).forEach( i -> {
Optional.of(Thread.currentThread().getName() + " " + i).ifPresent(System.out::println);
});
}
}
3. interrupt()
線程在執行過程中可以被中斷,調用interrupted()查看是否被中斷。
package com.juc;
import java.util.Optional;
import java.util.stream.IntStream;
public class ThreadInterrupt {
public static void main(String[] args) {
Thread thread = new Thread(()->{
IntStream.range(1, 10).forEach(
i -> {
try {
Thread.sleep(1_000);
} catch (InterruptedException e) {
System.out.println("線程被中斷 ");
}
Optional.of(i).ifPresent(System.out::println);
}
);
}, "thread");
thread.start();
try {
Thread.sleep(2_000);
} catch (InterruptedException e) {
e.printStackTrace();
}
thread.interrupt();
}
}
4. setPriority()、線程優先級
package com.juc;
import java.util.Optional;
import java.util.stream.IntStream;
/**
* @Description Thread類相關的API
*/
public class ThreadAPI {
public static void main(String[] args) {
Thread thread1 = new Thread( ()-> {
printInfo();
}, "thread1");
Thread thread2 = new Thread( ()-> {
printInfo();
}, "thread2");
Thread thread3 = new Thread( ()-> {
printInfo();
}, "thread3");
// priority: 優先級的設定有時並無意義,線程能否進入運行狀態取決於CPU是否有空閒的時間片
thread1.setPriority(Thread.MAX_PRIORITY);
thread2.setPriority(Thread.NORM_PRIORITY);
thread3.setPriority(Thread.MIN_PRIORITY);
thread1.start();
thread2.start();
thread3.start();
}
// id,name: 一般來說,我們創建的第一個線程id爲11,前9個是必須線程,第10個是main
private static void printInfo() {
Thread c_thread = Thread.currentThread();
System.out.printf("============%s id: %s===============\n", c_thread.getName(), c_thread.getId());
IntStream.range(1, 10).forEach(i -> {
Optional.of(c_thread.getName() + " " + i).ifPresent(System.out::println);
});
}
}