java多線程設計——線程啓動,互斥,Single Threaded Execution

1.線程的啓動

順序,併發,並行

順序:用於表示多個操作“依次處理”。比如把十個操作交給一個人處理,這個人就得一個一個地按順序來處理

並行:用於表示多個操作“同時處理”。比如把十個操作交給兩個人處理,這兩個人就會並行處理。

併發:將操作打散成多個步驟,然後依次執行,就像是說一個人同時做好幾件事,但是

他執行的動作是先做這件事,然後停下來再做另一件事。

 

實際上運行的線程就像上面這樣在不斷切換,順序執行併發處理。

程序的終止:

Java程序的終止是指除守護線程以外的線程全部終止。守護線程是執行後臺作業的線程。通過setDaemon()設置守護線程。

 

線程的啓動1Thread類繼承

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();

}

}

線程的啓動2Runnable接口實現

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.classSomething類對應的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

Gate 類:
public class Gate {
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()表示當前正在使用的資源個數

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章