目錄
1 線程停止
Thread的stop方法已過時,通常情況下需要程序員自己寫一些方法讓線程停止。
通常可以在線程內部做一個flag標識,通過flag判斷線程是否繼續執行
public class ThreadStop {
public static void main(String[] args){
RunnableThread rt = new RunnableThread();
Thread thr = new Thread(rt);
thr.start();
for(int i = 1; i <= 20; i++){
if(i == 10){
rt.stop();
}
System.out.println("主線程:"+i);
}
}
}
class RunnableThread implements Runnable{
private volatile boolean flag = true;
int i = 0;
@Override
public void run() {
while(flag){
i++;
System.out.println("RunnableThread執行第"+i+"次");
}
}
public void stop(){
this.flag = false;
System.out.println("RunnableThread線程停止");
}
}
2 線程讓步
調用Thread.yield();的當前線程會讓出CPU資源,然後重新參與資源競爭。競爭結果是有可能繼續佔用CPU資源,有可能不是
@Test
public void testYield() throws InterruptedException, ExecutionException {
RunnableThread runnableThread = new RunnableThread();
Thread thr = new Thread(runnableThread);
thr.start();
for (int i = 1; i <= 100; i++) {
System.out.println(i);
// 主線程每執行10次,讓步一次
if (i % 10 == 0) {
Thread.yield();
}
}
}
class RunnableThread implements Runnable {
boolean flag = true;
int i = 0;
@Override
public void run() {
while (flag) {
System.out.println(Thread.currentThread().getName() + "執行" + (i ++) + "次");
}
}
}
觀察輸出結果可以發現每次讓步後有可能主線程繼續運行,有可能切換到子線程運行
3 線程加入
@Test
public void testJoin() throws InterruptedException, ExecutionException {
RunnableThread runnableThread = new RunnableThread();
RunnableThread runnableThread2 = new RunnableThread();
Thread thr = new Thread(runnableThread, "子線程一");
Thread thr2 = new Thread(runnableThread2, "子線程二");
thr.start();
thr2.start();
for (int i = 1; i <= 100; i++) {
System.out.println(i);
// 主線程執行10次後然子線程加入
if (i == 10) {
thr.join();
}
}
}
class RunnableThread implements Runnable {
boolean flag = true;
int i = 0;
@Override
public void run() {
while (flag) {
System.out.println(Thread.currentThread().getName() + "執行" + (i ++) + "次");
if (i == 300) {
break;
}
}
}
}
觀察輸出結果可以發現主線程輸出10後兩個子線程交替執行。直到兩個子線程執行完畢,主線程才繼續運行
4 線程通信(wait和notify)
wait和notify是Object類的方法,某個對象執行wait或notify的時候當前線程一定要先獲取到synchronized鎖,否則會報IllegalMonitorStateException,有興趣的同學可以研究一下相關的JIN方法
實現功能:創建兩個線程,交替輸出各自線程的名字
/**
* 當前標誌位
*/
private volatile int flag = 0;
/**
* 定義一個鎖
*/
private final String lock = "";
@Test
public void testWaitAndNotify() throws InterruptedException, ExecutionException {
// 線程一執行標誌位是0,下個線程(線程二)執行標誌位是1
RunnableThread runnableThread = new RunnableThread(0, 1);
// 線程二執行標誌位是1,下個線程(線程一)執行標誌位是0
RunnableThread runnableThread2 = new RunnableThread(1, 0);
Thread thr = new Thread(runnableThread, "線程一");
Thread thr2 = new Thread(runnableThread2, "線程二");
thr.start();
thr2.start();
TimeUnit.HOURS.sleep(1);
}
class RunnableThread implements Runnable {
/**
* 當前線程執行標識
*/
private volatile int symbol;
/**
* 下個線程執行標識
*/
private volatile int next;
public RunnableThread(int symbol, int next) {
this.symbol = symbol;
this.next = next;
}
@Override
public void run() {
while (true) {
synchronized (lock) {
try {
Thread.sleep(500);
} catch (InterruptedException ignore) {}
if (flag != symbol) {
try {
// 調用wait和notify的方法一定要是synchronized鎖住的對象
lock.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
if (flag == symbol) {
System.out.println(Thread.currentThread().getName());
flag = next;
// 調用wait和notify的方法一定要是synchronized鎖住的對象
lock.notify();
}
}
}
}
}
這樣我們就可以在控制檯看到線程一,線程二交替輸出