您好,登錄后才能下訂單哦!
本篇文章給大家分享的是有關在java項目中如何實現(xiàn)同步多線程,小編覺得挺實用的,因此分享給大家學習,希望大家閱讀完這篇文章后可以有所收獲,話不多說,跟著小編一起來看看吧。
java多線程的同步方法實例代碼
先看一個段有關銀行存錢的代碼:
class Bank { private int sum; public void add(int num){ sum = sum + num; try { Thread.sleep(10); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("total num is : " + sum); } } class Custom implements Runnable{ private Bank b = new Bank(); @Override public void run() { for(int i = 3 ; i > 0 ; i--) b.add(100); } } public class BankDemo{ public static void main(String[] args) { Custom custom = new Custom(); Thread t1 = new Thread(custom); Thread t2 = new Thread(custom); t1.start(); t2.start(); } }
此代碼的運行結果為:
total num is : 100 total num is : 300 total num is : 400 total num is : 500 total num is : 500 total num is : 600
可以看出sum的值與預期的效果不太一樣;造成這種現(xiàn)象的原因有兩個:
1.程序存在兩個以上的子線程;
2.子線程中存在多條語句操作同一變量;
上述例子中:創(chuàng)建了兩個子線程·t1 和 t2,分別向銀行中存錢。但是可以看出銀行的實力隨著Custom的創(chuàng)建,只創(chuàng)建了一個對象。也就是說我們只操作一個數(shù)據(jù)變量即為銀行中錢的總數(shù)sum;當兩個子線程開啟的時候run方法中調用了bank的add方法,而add方法中有兩個語句都在操作sum一個sum的增加,一個是打印sum,當兩個子線程搶占cpu執(zhí)行各自的程序的時候會出現(xiàn):
當t1執(zhí)行到add以后,t2搶到了cpu的執(zhí)行權,執(zhí)行也是執(zhí)行了add語句,隨后打印出sum的值,這時候由于sum增加了兩次,所以打印出來的sum值為200。類推,假如這個時候t1又搶回了cpu的執(zhí)行權,因此又打印出一次200。
顯然這種現(xiàn)象是我們不希望產(chǎn)生的。我們希望一個線程存完錢然后打印出結果,之后才允許下一次添加操作。這就是多線程會產(chǎn)生的問題,線程不安全。
我們應盡量避免這種現(xiàn)象的發(fā)生,Java給我們提供了三種方法來解決這個問題:
第一種:同步代碼塊
//private Object obj = new Object(); public void add(int num) { synchronized (this) { sum = sum + num; try { Thread.sleep(10); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("total num is : " + sum); } }
將多線程中需要操作同一數(shù)據(jù)對象的語句使用同步代碼塊包含。同步代碼塊的原理就是:
1.java中每個對象都有一個內置鎖;
2.當程序運行到同步代碼塊的時候首先會獲取指定對象的鎖,這個鎖對于多個線程來說是唯一的。我們可以創(chuàng)建任意一個對象(obj)讓他當作同步代碼塊的鎖。
3.當程序中只有一個只有一個鎖的話我們還可以使用this,this代表當前執(zhí)行代碼所操作的實例對象的鎖。即擁有add方法的類的對象,即bank。
4.兩個并發(fā)線程訪問同一個對象object中的這個synchronized(this)同步代碼塊時,一個時間內只能有一個線程得到執(zhí)行。另一個線程必須等待當前線程執(zhí)行完這個代碼塊以后才能執(zhí)行該代碼塊。
這樣就可以操作同一個數(shù)據(jù)的多條語句只能在“同一段時間”只能被一個子線程所操作。
第二種 同步函數(shù)
public synchronized void add(int num) { sum = sum + num; try { Thread.sleep(10); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("total num is : " + sum); }
除了同步代碼塊以外我們還可以將需要同步的操作抽象成一個函數(shù),然后將這個函數(shù)用synchronized修飾,形成同步方法。比如上述例子中的add方法中的語句都在操作sum對象。我們就可以將add方法使用synchronized修飾。這樣也能達到代碼同步的效果。
同步方法使用的鎖其實就是 this。
值得一提的是:同步方法和同步代碼塊,在開發(fā)程序的時候我們更推薦使用同步代碼塊。
1.同步代碼塊可以綁定任意對象,而同步函數(shù)只能綁定該類對象this
2.如果多個線程使用同一個鎖的話,那么兩者均可以使用,如果存在多個鎖的(比如,在一個對象的同步方法里面調用另外一個對象的同步方法,則獲取了兩個對象的同步鎖),只能使用同步代碼塊。
靜態(tài)方法的同步
同步方法
public synchronized static void add(int num){}
同步代碼塊:
public synchronized void add(int num){ synchronized (Bank.Class) { } }
靜態(tài)方法的默認同步鎖是當前方法所在類的.class 對象,注意this與static不可以連用,所以不能使用this.Class
以上就是在java項目中如何實現(xiàn)同步多線程,小編相信有部分知識點可能是我們日常工作會見到或用到的。希望你能通過這篇文章學到更多知識。更多詳情敬請關注億速云行業(yè)資訊頻道。
免責聲明:本站發(fā)布的內容(圖片、視頻和文字)以原創(chuàng)、轉載和分享為主,文章觀點不代表本網(wǎng)站立場,如果涉及侵權請聯(lián)系站長郵箱:is@yisu.com進行舉報,并提供相關證據(jù),一經(jīng)查實,將立刻刪除涉嫌侵權內容。