Java的同步可以用synchronized關鍵字來實現(xiàn)。
成都創(chuàng)新互聯(lián)公司堅持“要么做到,要么別承諾”的工作理念,服務領域包括:成都網(wǎng)站設計、成都做網(wǎng)站、企業(yè)官網(wǎng)、英文網(wǎng)站、手機端網(wǎng)站、網(wǎng)站推廣等服務,滿足客戶于互聯(lián)網(wǎng)時代的舟山網(wǎng)站設計、移動媒體設計的需求,幫助企業(yè)找到有效的互聯(lián)網(wǎng)解決方案。努力成為您成熟可靠的網(wǎng)絡建設合作伙伴!
sychronized可以同步代碼,需要綁定一個對象,如synchronized(obj){}
也可以同步一個方法,是對方法進行線程同步。如public void synchronized methodA(){}
1.同步方法 即有synchronized關鍵字修飾的方法。 由于java的每個對象都有一個內置鎖,當用此關鍵字修飾方法時, 內置鎖會保護整個方法。在調用該方法前,需要獲得內置鎖,否則就處于阻塞狀態(tài)。 代碼如: public synchronized void save(){} 注: synchronized關鍵字也可以修飾靜態(tài)方法,此時如果調用該靜態(tài)方法,將會鎖住整個類 2.同步代碼塊 即有synchronized關鍵字修飾的語句塊。 被該關鍵字修飾的語句塊會自動被加上內置鎖,從而實現(xiàn)同步 代碼如: synchronized(object){ } 注:同步是一種高開銷的操作,因此應該盡量減少同步的內容。 通常沒有必要同步整個方法,使用synchronized代碼塊同步關鍵代碼即可。 代碼實例: 復制代碼package com.xhj.thread; /** * 線程同步的運用 * * @author XIEHEJUN * */ public class SynchronizedThread { class Bank { private int account = 100; public int getAccount() { return account; } /** * 用同步方法實現(xiàn) * * @param money */ public synchronized void save(int money) { account += money; } /** * 用同步代碼塊實現(xiàn) * * @param money */ public void save1(int money) { synchronized (this) { account += money; } } } class NewThread implements Runnable { private Bank bank; public NewThread(Bank bank) { this.bank = bank; } @Override public void run() { for (int i = 0; i 10; i++) { // bank.save1(10); bank.save(10); System.out.println(i + "賬戶余額為:" + bank.getAccount()); } } } /** * 建立線程,調用內部類 */ public void useThread() { Bank bank = new Bank(); NewThread new_thread = new NewThread(bank); System.out.println("線程1"); Thread thread1 = new Thread(new_thread); thread1.start(); System.out.println("線程2"); Thread thread2 = new Thread(new_thread); thread2.start(); } public static void main(String[] args) { SynchronizedThread st = new SynchronizedThread(); st.useThread(); } }復制代碼 3.使用特殊域變量(volatile)實現(xiàn)線程同步 a.volatile關鍵字為域變量的訪問提供了一種免鎖機制, b.使用volatile修飾域相當于告訴虛擬機該域可能會被其他線程更新, c.因此每次使用該域就要重新計算,而不是使用寄存器中的值 d.volatile不會提供任何原子操作,它也不能用來修飾final類型的變量 例如: 在上面的例子當中,只需在account前面加上volatile修飾,即可實現(xiàn)線程同步。 代碼實例: 復制代碼 //只給出要修改的代碼,其余代碼與上同 class Bank { //需要同步的變量加上volatile private volatile int account = 100; public int getAccount() { return account; } //這里不再需要synchronized public void save(int money) { account += money; } }復制代碼 注:多線程中的非同步問題主要出現(xiàn)在對域的讀寫上,如果讓域自身避免這個問題,則就不需要修改操作該域的方法。 用final域,有鎖保護的域和volatile域可以避免非同步的問題。 4.使用重入鎖實現(xiàn)線程同步 在JavaSE5.0中新增了一個java.util.concurrent包來支持同步。 ReentrantLock類是可重入、互斥、實現(xiàn)了Lock接口的鎖, 它與使用synchronized方法和快具有相同的基本行為和語義,并且擴展了其能力 ReenreantLock類的常用方法有: ReentrantLock() : 創(chuàng)建一個ReentrantLock實例 lock() : 獲得鎖 unlock() : 釋放鎖 注:ReentrantLock()還有一個可以創(chuàng)建公平鎖的構造方法,但由于能大幅度降低程序運行效率,不推薦使用 例如: 在上面例子的基礎上,改寫后的代碼為: 代碼實例: 復制代碼//只給出要修改的代碼,其余代碼與上同 class Bank { private int account = 100; //需要聲明這個鎖 private Lock lock = new ReentrantLock(); public int getAccount() { return account; } //這里不再需要synchronized public void save(int money) { lock.lock(); try{ account += money; }finally{ lock.unlock(); } } }復制代碼 注:關于Lock對象和synchronized關鍵字的選擇: a.最好兩個都不用,使用一種java.util.concurrent包提供的機制, 能夠幫助用戶處理所有與鎖相關的代碼。 b.如果synchronized關鍵字能滿足用戶的需求,就用synchronized,因為它能簡化代碼 c.如果需要更高級的功能,就用ReentrantLock類,此時要注意及時釋放鎖,否則會出現(xiàn)死鎖,通常在finally代碼釋放鎖 5.使用局部變量實現(xiàn)線程同步 如果使用ThreadLocal管理變量,則每一個使用該變量的線程都獲得該變量的副本, 副本之間相互獨立,這樣每一個線程都可以隨意修改自己的變量副本,而不會對其他線程產(chǎn)生影響。 ThreadLocal 類的常用方法 ThreadLocal() : 創(chuàng)建一個線程本地變量 get() : 返回此線程局部變量的當前線程副本中的值 initialValue() : 返回此線程局部變量的當前線程的"初始值" set(T value) : 將此線程局部變量的當前線程副本中的值設置為value 例如: 在上面例子基礎上,修改后的代碼為: 代碼實例: 復制代碼//只改Bank類,其余代碼與上同 public class Bank{ //使用ThreadLocal類管理共享變量account private static ThreadLocalInteger account = new ThreadLocalInteger(){ @Override protected Integer initialValue(){ return 100; } }; public void save(int money){ account.set(account.get()+money); } public int getAccount(){ return account.get(); } }復制代碼 注:ThreadLocal與同步機制 a.ThreadLocal與同步機制都是為了解決多線程中相同變量的訪問沖突問題。 b.前者采用以"空間換時間"的方法,后者采用以"時間換空間"的方式。
1。同步代碼塊:
synchronized(同一個數(shù)據(jù)){} 同一個數(shù)據(jù):就是N條線程同時訪問一個數(shù)據(jù)。
2。
同步方法:
public synchronized 數(shù)據(jù)返回類型 方法名(){}
就
是使用 synchronized 來修飾某個方法,則該方法稱為同步方法。對于同步方法而言,無需顯示指定同步監(jiān)視器,同步方法的同步監(jiān)視器是
this
也就是該對象的本身(這里指的對象本身有點含糊,其實就是調用該同步方法的對象)通過使用同步方法,可非常方便的將某類變成線程安全的類,具有如下特征:
1,該類的對象可以被多個線程安全的訪問。
2,每個線程調用該對象的任意方法之后,都將得到正確的結果。
3,每個線程調用該對象的任意方法之后,該對象狀態(tài)依然保持合理狀態(tài)。
注:synchronized關鍵字可以修飾方法,也可以修飾代碼塊,但不能修飾構造器,屬性等。
實現(xiàn)同步機制注意以下幾點: 安全性高,性能低,在多線程用。性能高,安全性低,在單線程用。
1,不要對線程安全類的所有方法都進行同步,只對那些會改變共享資源方法的進行同步。
2,如果可變類有兩種運行環(huán)境,當線程環(huán)境和多線程環(huán)境則應該為該可變類提供兩種版本:線程安全版本和線程不安全版本(沒有同步方法和同步塊)。在單線程中環(huán)境中,使用線程不安全版本以保證性能,在多線程中使用線程安全版本.
線程通訊:
為什么要使用線程通訊?
當
使用synchronized
來修飾某個共享資源時(分同步代碼塊和同步方法兩種情況),當某個線程獲得共享資源的鎖后就可以執(zhí)行相應的代碼段,直到該線程運行完該代碼段后才釋放對該
共享資源的鎖,讓其他線程有機會執(zhí)行對該共享資源的修改。當某個線程占有某個共享資源的鎖時,如果另外一個線程也想獲得這把鎖運行就需要使用wait()
和notify()/notifyAll()方法來進行線程通訊了。
Java.lang.object 里的三個方法wait() notify() notifyAll()
wait方法導致當前線程等待,直到其他線程調用同步監(jiān)視器的notify方法或notifyAll方法來喚醒該線程。
wait(mills)方法
都是等待指定時間后自動蘇醒,調用wait方法的當前線程會釋放該同步監(jiān)視器的鎖定,可以不用notify或notifyAll方法把它喚醒。
notify()
喚醒在同步監(jiān)視器上等待的單個線程,如果所有線程都在同步監(jiān)視器上等待,則會選擇喚醒其中一個線程,選擇是任意性的,只有當前線程放棄對該同步監(jiān)視器的鎖定后,也就是使用wait方法后,才可以執(zhí)行被喚醒的線程。
notifyAll()方法
喚醒在同步監(jiān)視器上等待的所有的線程。只用當前線程放棄對該同步監(jiān)視器的鎖定后,才可以執(zhí)行被喚醒的線程
線程同步主要有以下種方法(示例中是實現(xiàn)計數(shù)的功能):
1、同步方法,即使用synchronized關鍵字修飾方法,例如:
public?synchronized?void?add(int?c){...}
2、同步代碼塊,即有synchronized關鍵字修飾的語句塊,例如:
public?void?addAndGet(int?c){
synchronized(this){
count?+=?c;
}
}
3、使用特殊域變量(volatile)實現(xiàn)線程同步,該方法不能保證絕對的同步。
例如:private?volatile?int?count?=?0;
4、使用鎖實現(xiàn)線程同步,例如:
private?Lock?lock?=?new?ReentrantLock();
public?void?add(int?c)?{??
lock.lock();//上鎖??
try{??
count?+=?c;??
}finally{??
lock.unlock();//解鎖??
}??
}
5、使用原子變量實現(xiàn)線程同步,在java的util.concurrent.atomic包中提供了創(chuàng)建了原子類型變量的工具類,例如:
private?AtomicInteger?count=?new?AtomicInteger(1);
public?void?add(int?c)?{
count.addAndGet(c);
}
6、使用局部變量實現(xiàn)線程同步,如果使用ThreadLocal管理變量,則每一個使用該變量的線程都獲得該變量的副本, 副本之間相互獨立,這樣每一個線程都可以隨意修改自己的變量副本,而不會對其他線程產(chǎn)生影響。
ThreadLocal 類的常用方法
new ThreadLocalT() : 創(chuàng)建一個線程本地變量
get() : 返回此線程局部變量的當前線程副本中的值
initialValue() : 返回此線程局部變量的當前線程的"初始值"
set(T value) : 將此線程局部變量的當前線程副本中的值設置為value
示例代碼:
private?static?ThreadLocalInteger?count=?new?ThreadLocalInteger(){
@Override
protected?Integer?initialValue(){?
return?1;
}
};????????????
public?void?add(int?c){
count.set(count.get()?+?c);
}
7、使用阻塞隊列實現(xiàn),例如LinkedBlockingQueue,具體使用可百度LinkedBlockingQueue的用法或查看java文檔。
Java的同步可以用synchronized關鍵字來實現(xiàn)。
sychronized可以同步代碼,需要綁定一個對象,如synchronized(obj){}
也可以同步一個方法,是對方法進行線程同步。如public void synchronized methodA(){}
分享文章:java如何同步代碼 java 同步代碼塊
分享地址:http://jinyejixie.com/article48/hpcghp.html
成都網(wǎng)站建設公司_創(chuàng)新互聯(lián),為您提供域名注冊、網(wǎng)站維護、網(wǎng)站內鏈、ChatGPT、外貿(mào)網(wǎng)站建設、關鍵詞優(yōu)化
聲明:本網(wǎng)站發(fā)布的內容(圖片、視頻和文字)以用戶投稿、用戶轉載內容為主,如果涉及侵權請盡快告知,我們將會在第一時間刪除。文章觀點不代表本網(wǎng)站立場,如需處理請聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內容未經(jīng)允許不得轉載,或轉載時需注明來源: 創(chuàng)新互聯(lián)