1.線程的啓動
順序,併發,並行
順序:用於表示多個操作“依次處理”。比如把十個操作交給一個人處理,這個人就得一個一個地按順序來處理
並行:用於表示多個操作“同時處理”。比如把十個操作交給兩個人處理,這兩個人就會並行處理。
併發:將操作打散成多個步驟,然後依次執行,就像是說一個人同時做好幾件事,但是
他執行的動作是先做這件事,然後停下來再做另一件事。
實際上運行的線程就像上面這樣在不斷切換,順序執行併發處理。
程序的終止:
Java程序的終止是指除守護線程以外的線程全部終止。守護線程是執行後臺作業的線程。通過setDaemon()設置守護線程。
線程的啓動1:Thread類繼承
public class PrintThread extends Thread{
private String msg;
public PrintThread(String msg) {
super();
this.msg = msg;
}
public void run(){
for (int i = 0; i < 10000; i++) {
System.out.println(msg);
}
}
public static void main(String[] args) {
new PrintThread("God!").start();
new PrintThread("Nice!").start();
}
}
線程的啓動2:Runnable接口實現
public class Printer implements Runnable {
private String msg;
public Printer(String msg) {
super();
this.msg = msg;
}
@Override
public void run() {
// TODO Auto-generated method stub
for (int i = 0; i < 10000; i++) {
System.out.println(msg);
}
}
public static void main(String[] args) {
new Thread(new Printer("Good!")).start();
new Thread(new Printer("bad!")).start();
ThreadFactory factory = Executors.defaultThreadFactory();
factory.newThread(new Printer("XSM")).start();
}
}
利用ThreadFactory啓動線程:
ThreadFactory factory = Executors.defaultThreadFactory();
factory.newThread(new Printer("XSM")).start();
線程的暫停:
Thread.sleep(1000);//暫停1s
2. 線程的互斥處理
多線程程序中的各個線程是自由運行的,所以他們有時會操作同一個案例
Synchronized方法處理互斥問題
Synchronized每次只能由一個線程執行,線程運行完synchornized方法後,釋放鎖
鎖和監視:
獲取鎖有時叫做“擁有監視”或者“持有鎖”
當前線程是否已獲取某一對象的鎖通過Thread.holdsLock方法確認,當前線程已獲取對象obj的鎖時,可使用assert來表示:
Assert Thread.holdsLock(obj);
每個實例都有獨立的鎖;如圖bank1,bank2
synchronized代碼塊
Synchronized(表達式){
}
synchronized實例方法和synchronized代碼塊
Sychronzied void method(){
}
等效於
void method(){
Synchronized(this){
}
}
synchronized靜態方法和synchronized代碼塊
synchronized靜態方法是使用該類對象的鎖來執行線程的互斥處理的,Somthing.class是Something類對應的java.lang.class類的實例
線程協作:
假如需要執行更精確的控制,而不是單純的等待其他線程運行終止
例如:
如果空間爲空則寫入數據,如果非空則一直等待到變空爲止
空間已爲空時,“通知”正在等待的線程
wait方法:將線程放入 等待隊列
如果要執行wait方法 ,線程必須持有鎖,如圖:
當線程A進入等待隊列的時候,會釋放鎖,這個時候線程B就會獲取到
notify方法---從等待隊列中取出線程
notify 方法會將等待隊列中的一個線程取出。如圖
線程A退出等待隊列,想要進入wait的下一個操作,但剛纔執行notify的線程B仍癡有鎖
剛纔執行notify的線程B釋放了鎖
notifyAll----從等待隊列中取出所有線程
概念小結:
某個線程在運行synchronized方法時,其他所有線程都會停止運行(錯)
停止運行的只是想要獲取同一個實例的鎖的線程。
wait方法的調用必須在synchronized方法中(錯)
調用wait方法的語句可以寫在synchronized方法中和代碼塊中,或者二者調用的其他方法中,只要執行方法的線程在執行時獲取了對象實例的鎖即可。
3. Single Threaded Execution
private int counter = 0;
private String name = "Nobody";
private String address = "Nowhere";
public void pass(String name,String address){
this.counter++;
this.name = name;
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
this.address = address;
check();
}
public String toStr(){
return "No." + counter+":"+name+","+address;
}
public void check(){
if(name.charAt(0)!= address.charAt(0)){
System.out.println("Broken"+toStr());
}
}
}
UserThread類:
public class UserThread extends Thread{
private final Gate gate;
private final String myname;
private final String myaddress;
public UserThread2(Gate gate, String myname, String myaddress) {
this.gate = gate;
this.myname = myname;
this.myaddress = myaddress;
}
public void run(){
System.out.println(myname+"begin");
while(true){
gate.pass(myname, myaddress);
}
}
}
public static void main{
Gate gate = new Gate();
new UserThread(gate, "Alice", "Asian").start();
new UserThread(gate, "Bobby", "Brazil").start();
new UserThread(gate, "Chris", "Canada").start();
this.counter++;
this.name = name;
this.address = address;
check();
}
解決方法:在pass()方法前加上synchronized
使用Single Threaded Execution模式的情況
1.多線程時
2.數據可被多個線程訪問
3.狀態可能改變
4.需要確保數據安全性
在使用Single Threaded Execution,會存在發生死鎖的危險
1.存在多個SharedResource角色(參與者)
2.線程在持有着某個SharedResource角色的鎖的同時,還想獲取其他SharedResource角色的鎖
3.獲取SharedResource角色的鎖的順序並不固定
比喻兩個意大利喫拉麪的例子(兩個人吃麪只有一個勺子和叉子,但是勺子和叉子缺一不可,一個人拿着叉子,一個人拿着勺子):
1.存在多個SharedResource角色(參與者)相當於叉子和勺子
2.線程在持有着某個SharedResource角色的鎖的同時,還想獲取其他SharedResource角色的鎖 相當於拿着叉子還想要勺子
3.獲取SharedResource角色的鎖的順序並不固定 拿叉子和拿勺子的順序並不一樣
繼承反覆性:
對於多線程來說,繼承會出現很多問題
.Single Threaded Execution 降低程序性能
1. 獲取鎖花費的時間
2. 線程衝突引起的等待
Semaphore的使用
semaphone.acquire()用於確認是否存在可用資源,當所有資源已被使用時,線程會阻塞在此方法中
semaphone.release()方法釋放所用的資源
semaphone.avaliablePermits()表示當前正在使用的資源個數