請說出與線程同步以及線程調度相關的方法。


wait():使一個線程處於等待(阻塞)狀態,並且釋放所持有的對象的鎖;sleep():使一個正在運行的線程處於睡眠狀態,是一個靜態方法,調用此方法要處理 InterruptedException 異常;

notify():喚醒一個處於等待狀態的線程,當然在調用此方法的時候,並不能確切的喚醒某一個等待狀態的線程,而是由 JVM 確定喚醒哪個線程,而且與優先級無關;

notityAll():喚醒所有處於等待狀態的線程,該方法並不是將對象的鎖給所有線程,而是讓它們競爭,只有獲得鎖的線程才能進入就緒狀態;

提示:關於 Java 多線程和並發編程的問題,建議大家看我的另一篇文章《關於 Java並發編程的總結和思考》

補充:Java 5 通過 Lock 接口提供了顯式的鎖機制(explicit lock),增強了靈活性以及對線程的協調。Lock 接口中定義了加鎖(lock())和解鎖(unlock())的方法,同時還提供了 newCondition()方法來產生用於線程之間通信的 Condition 對象;此外,Java 5 還提供了信號量機制(semaphore),信號量可以用來限制對某個共享資源進行訪問的線程的數量。在對資源進行訪問之前,線程必須得到信號量的許可(調用 Semaphore 對象的 acquire()方法);在完成對資源的訪問后,

線程必須向信號量歸還許可(調用 Semaphore 對象的 release()方法)。

下面的例子演示了 100 個線程同時向一個銀行賬戶中存入 1 元錢,在沒有使用同步機制和使用同步機制情況下的執行情況。

 

銀行賬戶類:

/**

* 銀行賬戶

* @author

*

*/

public class Account {

private double balance;

// 賬戶余額

/**

* 存款

* @param money 存入金額

*/

public void deposit(double money) {

double newBalance = balance + money;

try {

Thread.sleep(10);

// 模擬此業務需要一段處理時間

}

catch(InterruptedException ex) {

ex.printStackTrace();

}

balance = newBalance;

}

/**

* 獲得賬戶余額

*/

public double getBalance() {

return balance;

}

}

存錢線程類:

/**

* 存錢線程

* @author

*

*/

public class AddMoneyThread implements Runnable {

private Account account;

// 存入賬戶

private double money;

// 存入金額

public AddMoneyThread(Account account, double money) {

this.account = account;

this.money = money;

}

@Override

public void run() {

account.deposit(money);

}

}

測試類:

import java.util.concurrent.ExecutorService;

import java.util.concurrent.Executors;

public class Test01 {

public static void main(String[] args) {

Account account = new Account();

ExecutorService service = Executors.newFixedThreadPool(100);

for(int i = 1; i <= 100; i++) {

service.execute(new AddMoneyThread(account, 1));

}

service.shutdown();

while(!service.isTerminated()) {}

System.out.println("賬戶余額: " + account.getBalance());

}

}

在沒有同步的情況下,執行結果通常是顯示賬戶余額在 10 元以下,出現這種狀況的原因是,當一個線程 A 試圖存入 1 元的時候,另外一個線程 B 也能夠進入存款

的方法中,線程 B 讀取到的賬戶余額仍然是線程 A 存入 1 元錢之前的賬戶余額,因此也是在原來的余額 0 上面做了加 1 元的操作,同理線程 C 也會做類似的事情,

所以最后 100 個線程執行結束時,本來期望賬戶余額為 100 元,但實際得到的通常在 10 元以下(很可能是 1 元哦)。解決這個問題的辦法就是同步,當一個線程

對銀行賬戶存錢時,需要將此賬戶鎖定,待其操作完成后才允許其他的線程進行操作,代碼有如下幾種調整方案:

在銀行賬戶的存款(deposit)方法上同步(synchronized)關鍵字

/**

* 銀行賬戶

* @author

*

*/

public class Account {

private double balance;

// 賬戶余額

/**

* 存款

* @param money 存入金額

*/

public synchronized void deposit(double money) {

double newBalance = balance + money;

try {

Thread.sleep(10);

// 模擬此業務需要一段處理時間

}

catch(InterruptedException ex) {

ex.printStackTrace();

}

balance = newBalance;

}

/**

* 獲得賬戶余額

*/

public double getBalance() {

return balance;

}

}

在線程調用存款方法時對銀行賬戶進行同步

/**

* 存錢線程

* @author 駱昊

*

*/

public class AddMoneyThread implements Runnable {

private Account account;

// 存入賬戶

private double money;

// 存入金額

public AddMoneyThread(Account account, double money) {

this.account = account;

this.money = money;

}

@Override

public void run() {

synchronized (account) {

account.deposit(money);

}

}

}

 

通過 Java 5 顯示的鎖機制,為每個銀行賬戶創建一個鎖對象,在存款操

作進行加鎖和解鎖的操作

import java.util.concurrent.locks.Lock;

import java.util.concurrent.locks.ReentrantLock;

/**

* 銀行賬戶

*

* @author 駱昊

*

*/

public class Account {

private Lock accountLock = new ReentrantLock();

private double balance; // 賬戶余額

/**

* 存款

*

* @param money

*

存入金額

*/

public void deposit(double money) {

accountLock.lock();

try {

double newBalance = balance + money;

try {

Thread.sleep(10); // 模擬此業務需要一段處理時間

}

catch (InterruptedException ex) {

ex.printStackTrace();

}

balance = newBalance;

}

finally {

accountLock.unlock();

}

}

/**

* 獲得賬戶余額

*/public double getBalance() {

return balance;

}

}

按照上述三種方式對代碼進行修改后,重寫執行測試代碼 Test01,將看到最終的賬戶余額為 100 元。當然也可以使用 Semaphore 或 CountdownLatch 來實現同步。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM