文章出處 https://www.jianshu.com/p/744c4e65a3b3
文章對應視頻出處:https://developer.aliyun.com/course/1012?spm=5176.10731542.0.0.6ef2d290hxQ4g0
在多線操作之中如果要啓動多線程使用的是Thread類中的start()方法,而如果對於多線程需要進行停止處理,Thread類原本提供了stop()方法,但是對於這些方法從JDK1.2版本就已經廢除了,而且一直到現在也不再建議使用,而除了stop()之外還有幾個方法也被禁用了:
- 停止多線程:public final void stop();
- 銷燬多線程:public void destroy();
- 掛起線程:public final void suspend()、暫停執行;
- 恢復掛起的線程執行:public final void resume();
之所以廢除掉這些方法,主要原因是因爲這些方法可能導致線程死鎖,所以從JDK1.2後開始都不再建議使用了。所以,如果要想實現線程的停止需要通過一種柔和的方式來進行。
範例:實現線程柔和的停止
public class ThreadDemo {
public static boolean flag = true;
public static void main(String[] args) throws Exception {
new Thread(() -> {
long num = 0;
while (flag) {
try {
Thread.sleep(50);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + "正在運行、num = " + num++);
}
}, "執行線程").start();
Thread.sleep(200);//運行200毫秒
flag = false;//停止線程
}
}
萬一現在有其他線程去控制這個flag的內容,那麼這個時候對於線程的停止也不是說停就立刻停止的,而是會在執行中判斷flag的內容來完成。
守護線程
現在假設有一個保鏢,那麼這個保鏢一定是在僱主活着時候進行守護,僱主死了,保鏢就沒用了。所以在多線程中可進行守護線程的定義,也就是說如果現在主線程的程序或者其他線程還在執行的時候,那麼守護線程將一直存在,並且運行在後臺狀態。
在Thread類中提供有如下的守護線程的操作方法:
- 設置爲守護線程:public final void setDaemon(boolean on);
- 判斷是否爲守護線程:public final boolean isDaemon();
範例:使用守護線程
public class ThreadDemo {
public static void main(String[] args) throws Exception {
Thread userThread = new Thread(() -> {
for (int i = 0; i < 10; i++) {
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + "正在運行、x = " + i);
}
}, "用戶線程");//完成核心業務
Thread deamonThread = new Thread(() -> {
for (int i = 0; i < Integer.MAX_VALUE; i++) {
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + "正在運行、x = " + i);
}
}, "守護線程");//完成核心業務
userThread.start();
deamonThread.setDaemon(true);//設置爲守護線程
deamonThread.start();
}
}
}
可以發現所有的守護線程都是圍繞在用戶線程的周圍,如果程序執行完畢了,守護線程也就消失了,在整個JVM中最大的守護線程就是GC線程。
程序執行中GC線程會一直存在,如果程序執行完畢,GC線程也將消失。
volatile關鍵字
在多線程定義中,volatile關鍵字主要是在屬性上使用的,表示此屬性爲直接數據操作,而不進行副本的拷貝處理。在一些書上就錯誤的理解爲同步屬性了。
在正常進行變量處理的時候往往會經歷如下的幾個步驟:
- 獲取變量的數據內容;
- 爲變量進行數學計算;
-
將計算後的變量,保存到原始空間之中;
而如果一個屬性上追加了volatile關鍵字,表示的就是不使用副本,而是直接操作原始變量,相當於節約了拷貝副本、重新保存的步驟。
class MyThread implements Runnable {
private volatile int ticket = 5;//直接內存操作
@Override
public void run() {
synchronized (this){
while (this.ticket > 0) {
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + "賣票,ticket = " + this.ticket--);
}
}
}
}
public class ThreadDemo {
public static void main(String[] args) throws Exception {
MyThread mt = new MyThread();
new Thread(mt, "票販子A").start();
new Thread(mt, "票販子B").start();
new Thread(mt, "票販子C").start();
}
}