本文主要介紹線程的相關調度方法
1.sleep()方法
讓當前線程暫停執⾏,從運⾏狀態進⼊阻塞狀態,將 CPU 資源讓給其他線程的調度⽅式,通過 sleep()來實現。
sleep(long millis),調⽤時需要傳⼊休眠時間,單位爲豪秒。
自定義一個線程類
public class MyThread extends Thread {
@Override
public void run() {
for (int i=0;i<10;i++){
if (i == 5){
try {
sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println(i + "------MyThread1");
}
}
}
test類
public class MyTest {
public static void main(String[] args) {
MyThread thread1 = new MyThread();
thread1.setName("線程1");
thread1.start();
}
}
控制檯上可發現運行到i = 4的時候,停了一秒鐘。
2.線程合併-join方法
合併是指將指定的某個線程加⼊到當前線程中,合併爲⼀個線程,由兩個線程交替執⾏變成⼀個線程中的兩個子線程順序執⾏。
通過調⽤ join ⽅法來實現合併,具體如何合併?
線程甲和線程⼄,線程甲執⾏到某個時間點的時候調⽤線程⼄的 join⽅法,則表示從當前時間點開始CPU 資源被線程⼄獨佔,線程甲進⼊阻塞狀態,直到線程⼄執⾏完畢,線程甲進⼊就緒狀態,等待獲取CPU 資源進⼊運⾏狀態。
join ⽅法重載,join() 表示⼄線程執⾏完畢之後才能執⾏其他線程,join(long millis) 表示⼄線程執⾏millis 毫秒之後,⽆論是否執⾏完畢,其他線程都可以和它爭奪 CPU 資源。
代碼演示:
自定義runable實現類
public class MyRunable1 implements Runnable {
@Override
public void run() {
for (int i = 0;i < 200; i++){
System.out.println("----MyRunable");
}
}
}
測試類
public class MyTest {
public static void main(String[] args) {
/*
* sleep()
* */
/*MyThread thread1 = new MyThread();
thread1.setName("線程1");
thread1.start();*/
/*
* join()-線程合併
* */
MyRunable1 runable1 = new MyRunable1();
Thread thread1 = new Thread(runable1);
thread1.start();
for (int i = 0;i < 100; i++){
if (i == 20){
try {
thread1.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println(i + "我是主線程");
}
}
}
查看結果可發現,到19的時候主線程就停了,讓thread1執行完纔開始執行的。
join(1000)的效果就是,thread1執行了一秒後,主線程和thread1又開始互相搶佔資源,交替執行。
3. yield()-線程禮讓
線程禮讓是指在某個特定的時間點,讓線程暫停搶佔 CPU 資源的⾏爲,運⾏狀態/就緒狀態—》阻塞狀態,將 CPU 資源讓給其他線程來使⽤。
假如線程甲和線程⼄在交替執⾏,某個時間點線程甲做出了禮讓,所以在這個時間節點線程⼄擁有了CPU 資源,執⾏業務邏輯,但不代表線程甲⼀直暫停執⾏。
線程甲只是在特定的時間節點禮讓,過了時間節點,線程甲再次進⼊就緒狀態,和線程⼄爭奪 CPU 資源。
代碼演示:
thread1
public class MyThread1 extends Thread {
@Override
public void run() {
for (int i=0;i<10;i++){
if (i == 2){
yield();
}
System.out.println(Thread.currentThread().getName()+i+"=====Thread1");
}
}
}
thread2
public class MyThread2 extends Thread {
@Override
public void run() {
for (int i=0;i<10;i++){
System.out.println(Thread.currentThread().getName()+i+"Thread2======");
}
}
}
test類
public class MyTest {
public static void main(String[] args) {
/*
* sleep()
* */
/*MyThread thread1 = new MyThread();
thread1.setName("線程1");
thread1.start();*/
/*
* join()-線程合併
* */
/*MyRunable1 runable1 = new MyRunable1();
Thread thread1 = new Thread(runable1);
thread1.start();
for (int i = 0;i < 100; i++){
if (i == 20){
try {
thread1.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println(i + "我是主線程");
}*/
/*
* yield()-線程合併
* */
MyThread1 thread1 = new MyThread1();
thread1.setName("線程甲");
MyThread2 thread2 = new MyThread2();
thread2.setName("線程乙");
thread1.start();
thread2.start();
}
}
效果可能有些不佳,知道意思就行。
4.線程中斷
有很多種情況會造成線程停⽌運⾏:
- 線程執⾏完畢⾃動停⽌
- 線程執⾏過程中遇到錯誤拋出異常並停⽌
- 線程執⾏過程中根據需求⼿動停⽌
Java 中實現線程中斷有如下⼏個常⽤⽅法:
1.public void stop()
2.public void interrupt()
3.public boolean isInterrupted()
stop ⽅法在新版本的 JDK 已經不推薦使⽤,重點關注後兩個⽅法。
interrupt 是⼀個實例⽅法,當⼀個線程對象調⽤該⽅法時,表示中斷當前線程對象。
每個線程對象都是通過⼀個標誌位來判斷當前是否爲中斷狀態。
isInterrupted 就是⽤來獲取當前線程對象的標誌位:true 表示清除了標誌位,當前線程已經中斷;false 表示沒有清除標誌位,當前對象沒有中斷。
當⼀個線程對象處於不同的狀態時,中斷機制也是不同的。
1.創建狀態:實例化線程對象,不啓動。
public class Test {
public static void main(String[] args) {
Thread thread = new Thread();
System.out.println(thread.getState());
thread.interrupt();
System.out.println(thread.isInterrupted());
}
}
執行結果
NEW 表示當前線程對象爲創建狀態,false 表示當前線程並未中斷,因爲當前線程沒有啓動,不存在中斷,不需要清除標誌位。
public class Test2 {
public static void main(String[] args) {
// MyRunnable runnable = new MyRunnable();
// Thread thread = new Thread(runnable);
// thread.start();
Thread thread = new Thread(new Runnable() {
@Override
public void run() {
// TODO Auto-generated method stub
for(int i = 0; i < 10;i++) {
System.out.println(i+"---main");
}
}
});
thread.start();
System.out.println(thread.getState());
thread.interrupt();
System.out.println(thread.isInterrupted());
System.out.println(thread.getState());
}
}