Java 多線程詳解(三)------線程的同步

來源:互聯網
上載者:User

標籤:cat   使用   object   images   http   構造   current   cep   []   

Java 多線程詳解(一)------概念的引入:http://www.cnblogs.com/ysocean/p/6882988.html

Java 多線程詳解(二)------如何建立進程和線程:http://www.cnblogs.com/ysocean/p/6883491.html

 

介紹完如何建立進程以及線程了,那麼我們接著來看一個執行個體:

  利用多線程類比 3 個視窗賣票

 

第一種方法:繼承 Thread 類

 建立視窗類別 TicketSell 

package com.ys.thread;public class TicketSell extends Thread{//定義一共有 50 張票,注意聲明為 static,表示幾個視窗共用private static int num = 50;//調用父類構造方法,給線程命名public TicketSell(String string) {super(string);}@Overridepublic void run() {//票分 50 次賣完for(int i = 0 ; i < 50 ;i ++){if(num > 0){try {sleep(10);//類比賣票需要一定的時間} catch (InterruptedException e) {// 由於父類的 run()方法沒有拋出任何異常,根據繼承的原則,子類拋出的異常不能大於父類, 故我們這裡也不能拋出異常e.printStackTrace();}System.out.println(this.currentThread().getName()+"賣出一張票,剩餘"+(--num)+"張");}}}}

  建立主線程測試:

package com.ys.thread;public class TestTicket {public static void main(String[] args) {//建立 3 個視窗TicketSell t1 = new TicketSell("A視窗");TicketSell t2 = new TicketSell("B視窗");TicketSell t3 = new TicketSell("C視窗");//啟動 3 個視窗進行買票t1.start();t2.start();t3.start();}}

  結果:這裡我們省略了一些,根據電腦配置,結果會隨機出現不同

B視窗賣出一張票,剩餘48張A視窗賣出一張票,剩餘47張C視窗賣出一張票,剩餘49張C視窗賣出一張票,剩餘46張B視窗賣出一張票,剩餘44張A視窗賣出一張票,剩餘45張A視窗賣出一張票,剩餘43張...C視窗賣出一張票,剩餘5張A視窗賣出一張票,剩餘4張B視窗賣出一張票,剩餘3張A視窗賣出一張票,剩餘2張C視窗賣出一張票,剩餘3張B視窗賣出一張票,剩餘1張C視窗賣出一張票,剩餘0張A視窗賣出一張票,剩餘-1張

  

 

 

 

第二種方法:實現 Runnable 介面

  建立視窗類別 TicketSellRunnable

package com.ys.thread;public class TicketSellRunnable implements Runnable{//定義一共有 50 張票,繼承機制開啟線程,資源是共用的,所以不用加 staticprivate int num = 50;@Overridepublic void run() {//票分 50 次賣完for(int i = 0 ; i < 50 ;i ++){if(num > 0){try {//類比賣一次票所需時間Thread.sleep(10);} catch (InterruptedException e) {e.printStackTrace();}System.out.println(Thread.currentThread().getName()+"賣出一張票,剩餘"+(--num)+"張");}}}}

  建立主線程測試:

package com.ys.thread;public class TicketSellRunnableTest {public static void main(String[] args) {TicketSellRunnable t = new TicketSellRunnable();Thread t1 = new Thread(t,"A視窗");Thread t2 = new Thread(t,"B視窗");Thread t3 = new Thread(t,"C視窗");t1.start();t2.start();t3.start();}}

  結果:同理為了篇幅我們也省略了中間的一些結果

B視窗賣出一張票,剩餘49張C視窗賣出一張票,剩餘48張A視窗賣出一張票,剩餘49張B視窗賣出一張票,剩餘47張A視窗賣出一張票,剩餘45張......A視窗賣出一張票,剩餘4張C視窗賣出一張票,剩餘5張A視窗賣出一張票,剩餘3張B視窗賣出一張票,剩餘2張C視窗賣出一張票,剩餘1張B視窗賣出一張票,剩餘0張A視窗賣出一張票,剩餘-2張C視窗賣出一張票,剩餘-1張

  

 

結果分析:這裡出現了票數為 負數的情況,這在現實生活中肯定是不存在的,那麼為什麼會出現這樣的情況呢?

  

解決辦法分析:即我們不能同時讓超過兩個以上的線程進入到 if(num>0)的代碼塊中,不然就會出現上述的錯誤。我們可以通過以下三個辦法來解決:

1、使用 同步代碼塊

2、使用 同步方法

3、使用 鎖機制

 

①、使用同步代碼塊

文法:synchronized (同步鎖) {    //需要同步操作的代碼          }同步鎖:為了保證每個線程都能正常的執行原子操作,Java 線程引進了同步機制;同步鎖也叫同步監聽對象、同步監聽器、互斥鎖;Java程式運行使用的任何對象都可以作為同步監聽對象,但是一般我們把當前並發訪問的共同資源作為同步監聽對象注意:同步鎖一定要保證是確定的,不能相對於線程是變化的對象;任何時候,最多允許一個線程拿到同步鎖,誰拿到鎖誰進入代碼塊,而其他的線程只能在外面等著

  執行個體:

public void run() {//票分 50 次賣完for(int i = 0 ; i < 50 ;i ++){//這裡我們使用當前對象的位元組碼對象作為同步鎖synchronized (this.getClass()) {if(num > 0){try {//類比賣一次票所需時間Thread.sleep(10);} catch (InterruptedException e) {e.printStackTrace();}System.out.println(Thread.currentThread().getName()+"賣出一張票,剩餘"+(--num)+"張");}}}}

  

 

2、使用 同步方法

文法:即用  synchronized  關鍵字修飾方法

@Overridepublic void run() {//票分 50 次賣完for(int i = 0 ; i < 50 ;i ++){sell();}}private synchronized void sell(){if(num > 0){try {//類比賣一次票所需時間Thread.sleep(10);} catch (InterruptedException e) {e.printStackTrace();}System.out.println(Thread.currentThread().getName()+"賣出一張票,剩餘"+(--num)+"張");}}

  注意:不能直接用 synchronized 來修飾 run() 方法,因為如果這樣做,那麼就會總是第一個線程進入其中,而這個線程執行完所有操作,即賣完所有票了才會出來。

 

 

3、使用 鎖機制

  

public interface Lock

  主要方法:

  常用實作類別:

public class ReentrantLockextends Objectimplements Lock, Serializable
//一個可重新進入互斥Lock具有與使用synchronized方法和語句訪問的隱式監視鎖相同的基本行為和語義,但具有擴充功能。

  例子:

package com.ys.thread;import java.util.concurrent.locks.Lock;import java.util.concurrent.locks.ReentrantLock;public class TicketSellRunnable implements Runnable{//定義一共有 50 張票,繼承機制開啟線程,資源是共用的,所以不用加 staticprivate int num = 50;//建立一個鎖對象Lock l = new ReentrantLock();@Overridepublic void run() {//票分 50 次賣完for(int i = 0 ; i < 50 ;i ++){//擷取鎖l.lock();try {if(num > 0){//類比賣一次票所需時間Thread.sleep(10);System.out.println(Thread.currentThread().getName()+"賣出一張票,剩餘"+(--num)+"張");}} catch (Exception e) {e.printStackTrace();}finally{//釋放鎖l.unlock();}}}private void sell(){}}

  

  

 

Java 多線程詳解(三)------線程的同步

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.