Java 多執行緒(1)
Java 多執行緒(1)
1. 概述
瞭解作業系統後,想學 Java多執行緒 好久了。一開始我學習了《Think In Java》中的多執行緒,真心講的很好。但是,有的過於深刻。需要,自己慢慢體會、總結。所以,我又入手了《Java 多執行緒程式設計核心技術》。打算,回頭再看《Think In Java》。
我計劃以《Java 多執行緒程式設計核心技術》為線,寫一下自己對 Java多執行緒 的理解。
2. Java執行緒基礎
【1】執行緒安全
引起執行緒安全問題的主要因素是 不同執行緒對共享資源的訪問 。執行緒安全是學習 多執行緒技術 的一個關鍵問題。
這裡需要明白 什麼是對資源的共享訪問、什麼是不共享。看下面的程式碼:
package Multithreading; public class MyThread extends Thread{ private int count = 2; public MyThread(String name){ super(); this.setName(name); } @Override public void run() { super.run(); while (count > 0){ System.out.println(Thread.currentThread().getName() + "\tCount = " + count); count--; } } } package Multithreading; public class Run { public static void main(String[] args) { MyThread myThread0 = new MyThread("執行緒-0"); MyThread myThread1 = new MyThread("執行緒-1"); MyThread myThread2 = new MyThread("執行緒-2"); myThread0.start(); myThread1.start(); myThread2.start(); } }
很明顯,這裡為三個執行緒 訪問的是三個不同 的物件。所以,它們之間沒有影響,它們坑定執行緒安全。執行結果如下:
將上面的 Run類
改為如下:
package Multithreading; public class Run { public static void main(String[] args) { MyThread task = new MyThread("執行緒-0"); new Thread(task).start(); new Thread(task).start(); new Thread(task).start(); } }
得到如下結果:
可以看到這裡的 task物件
不再是 資源與執行緒兩種身份,這裡它只作為一種資源。所以,下面建立的三個匿名的執行緒是對同一個資源進行訪問的。所以,結果會發生改變,因為 Count <= 0
後其他的執行緒也發現並退出了。
共享同一個資源會造成 非執行緒安全。比如,一個執行緒正要讀某共享的資源,而現在排程到一個新的執行緒執行,這個新執行緒正好修改那個共享資源。以後,重新排程到原執行緒讀該共享資源時會發現它不是原來所需要的,這就是所謂的 “讀寫衝突”。如何解決這樣的問題呢,可以通過 加鎖 機制。。。
【2】this.getName()
的問題
在《Java 多執行緒程式設計核心技術》p17,對 this.getName() 方法有點疑問。於是,寫程式碼測試了一下:
package Multithreading;
public class CountOperate extends Thread {
@Override
public synchronized void run() {
super.run();
System.out.println("CountOperate---begin---CountOperate");
System.out.println("this.getName()\t" + this.getName());
System.out.println("this.isAlive()\t" + this.isAlive());
System.out.println("Thread\t" + Thread.currentThread().getName());
System.out.println("Thread\t" + Thread.currentThread().isAlive());
System.out.println("CountOperate----end----CountOperate");
}
}
package Multithreading;
public class Run {
public static void main(String[] args) {
CountOperate countOperate = new CountOperate();
countOperate.start();
Thread thread1 = new Thread(countOperate);
thread1.start();
}
}
執行結果如下:
分析結果可以看到,Thread類
對執行緒的命名方式,它是從 Thread-0 開始的。比如這裡的第一個 Thread物件countOperate ,它的 getName()
方法返回就是 Thread-0。而,第二個 Thread物件thread1,它的 getName()
方法返回就是 Thread-1。知道了這些後,就可以弄懂書上的結果了。
【3】interrupted()
與 isInterrupted()
為了區別它們,先看看它們的宣告
public static boolean interrupted() {
return currentThread().isInterrupted(true); //true 表示清理中斷標誌
}
public boolean isInterrupted() {
return isInterrupted(false); //false 表示不清理中斷標誌
}
通過分析它們的宣告,可以很清楚的認識它們。interrupted()
是靜態方法,它可以用來判斷當前執行執行緒的中斷標誌,可以在呼叫 currentThread()
看出來。而且,它還每次都清楚中斷標誌。對於 isInterrupted()
方法,它是用來判斷某個 執行緒物件 的中斷標誌,且它並不清理中斷標誌。
【4】異常法停止中斷
停止中斷的常用方法!
package Multithreading;
public class MyThread extends Thread{
@Override
public void run() {
super.run();
try {
for (int i = 0; i < 500000; i++) {
System.out.println("i = " + i);
if (this.isInterrupted()) {
System.out.println("已經進入停止狀態!我要退出!");
throw new InterruptedException();
}
}
}catch (Exception e){
System.out.println("進入退出異常!");
e.printStackTrace();
}
}
}
//ps:注意這裡 try-catch 的位置
package Multithreading;
public class Run {
public static void main(String[] args) throws InterruptedException {
MyThread myThread = new MyThread();
myThread.start();
Thread.sleep(1000);
myThread.interrupt();
}
}
【5】suspend 獨佔
在《Java 多執行緒程式設計核心技術》p38,書中說的不是很清楚(或者我的理解有誤)。這裡,仍然可以通過在最後使用 thread1.resume()
使得可以繼續執行。但是,不建議使用 suspend() 和 resume()
方法。
ps:在《Java 多執行緒程式設計核心技術》p40,是有一 很大機率 不列印 main end
。但是還是有機率輸出的。為了測試,可以在 i++;
後面新增 Thread.yield()
。
【6】執行緒優先順序的繼承特性
對於 繼承 的理解。這裡的繼承是說,新的執行緒在舊的執行緒上開啟而不同於類的繼承。
也就是說,在舊執行緒裡啟動的新執行緒擁有舊執行緒的優先順序。
3. 堅持。。。
第一章的結束,用了一上午效率有點低。
一天進步一點點。。。