java同步,java同步和非同步的區別

本文目錄一覽:

java中同步有幾種方式啊

1。同步代碼塊:

synchronized(同一個數據){} 同一個數據:就是N條線程同時訪問一個數據。

2。

同步方法:

public synchronized 數據返回類型 方法名(){}

是使用 synchronized 來修飾某個方法,則該方法稱為同步方法。對於同步方法而言,無需顯示指定同步監視器,同步方法的同步監視器是

this

也就是該對象的本身(這裡指的對象本身有點含糊,其實就是調用該同步方法的對象)通過使用同步方法,可非常方便的將某類變成線程安全的類,具有如下特徵:

1,該類的對象可以被多個線程安全的訪問。

2,每個線程調用該對象的任意方法之後,都將得到正確的結果。

3,每個線程調用該對象的任意方法之後,該對象狀態依然保持合理狀態。

註:synchronized關鍵字可以修飾方法,也可以修飾代碼塊,但不能修飾構造器,屬性等。

實現同步機制注意以下幾點: 安全性高,性能低,在多線程用。性能高,安全性低,在單線程用。

1,不要對線程安全類的所有方法都進行同步,只對那些會改變共享資源方法的進行同步。

2,如果可變類有兩種運行環境,當線程環境和多線程環境則應該為該可變類提供兩種版本:線程安全版本和線程不安全版本(沒有同步方法和同步塊)。在單線程中環境中,使用線程不安全版本以保證性能,在多線程中使用線程安全版本.

線程通訊:

為什麼要使用線程通訊?

使用synchronized

來修飾某個共享資源時(分同步代碼塊和同步方法兩種情況),當某個線程獲得共享資源的鎖後就可以執行相應的代碼段,直到該線程運行完該代碼段後才釋放對該

共享資源的鎖,讓其他線程有機會執行對該共享資源的修改。當某個線程佔有某個共享資源的鎖時,如果另外一個線程也想獲得這把鎖運行就需要使用wait()

和notify()/notifyAll()方法來進行線程通訊了。

Java.lang.object 里的三個方法wait() notify() notifyAll()

wait方法導致當前線程等待,直到其他線程調用同步監視器的notify方法或notifyAll方法來喚醒該線程。

wait(mills)方法

都是等待指定時間後自動蘇醒,調用wait方法的當前線程會釋放該同步監視器的鎖定,可以不用notify或notifyAll方法把它喚醒。

notify()

喚醒在同步監視器上等待的單個線程,如果所有線程都在同步監視器上等待,則會選擇喚醒其中一個線程,選擇是任意性的,只有當前線程放棄對該同步監視器的鎖定後,也就是使用wait方法後,才可以執行被喚醒的線程。

notifyAll()方法

喚醒在同步監視器上等待的所有的線程。只用當前線程放棄對該同步監視器的鎖定後,才可以執行被喚醒的線程

java中線程同步的幾種方法

線程同步主要有以下種方法(示例中是實現計數的功能):

1、同步方法,即使用synchronized關鍵字修飾方法,例如:

public synchronized void add(int c){…}

2、同步代碼塊,即有synchronized關鍵字修飾的語句塊,例如:

public void addAndGet(int c){

    synchronized(this){

      count += c;

    }

}

3、使用特殊域變數(volatile)實現線程同步,該方法不能保證絕對的同步。

例如:private volatile int count = 0;

4、使用鎖實現線程同步,例如:

private Lock lock = new ReentrantLock();

  public void add(int c) {  

        lock.lock();//上鎖  

        try{  

            count += c;  

        }finally{  

            lock.unlock();//解鎖  

        }  

    }

5、使用原子變數實現線程同步,在java的util.concurrent.atomic包中提供了創建了原子類型變數的工具類,例如:

private AtomicInteger count= new AtomicInteger(1);

public void add(int c) {

    count.addAndGet(c);

}

6、使用局部變數實現線程同步,如果使用ThreadLocal管理變數,則每一個使用該變數的線程都獲得該變數的副本, 副本之間相互獨立,這樣每一個線程都可以隨意修改自己的變數副本,而不會對其他線程產生影響。

ThreadLocal 類的常用方法

new ThreadLocalT() : 創建一個線程本地變數

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、使用阻塞隊列實現,例如LinkedBlockingQueue,具體使用可百度LinkedBlockingQueue的用法或查看java文檔。

java中實現同步的方法有哪兩種?

Java的同步可以用synchronized關鍵字來實現。\x0d\x0a \x0d\x0asychronized可以同步代碼,需要綁定一個對象,如synchronized(obj){}\x0d\x0a也可以同步一個方法,是對方法進行線程同步。如public void synchronized methodA(){}

JAVA 中的同步機制有什麼作用?

Java中的同步機制有四種:① ThreadLocal ② synchronized( ) ③ wait() 與 notify() ④ volatile

目的:都是為了解決多線程中的對同一變數的訪問衝突

(1)ThreadLocal 保證不同線程擁有不同實例,相同線程一定擁有相同的實例,即為每一個使用該變數的線程提供一個該變數值的副本,每一個線程都可以獨立改變自己的副本,而不是與其它線程的副本衝突。

(2)優勢:提供了線程安全的共享對象

(3)與其它同步機制的區別:同步機制是為了同步多個線程對相同資源的並發訪問,是為了多個線程之間進行通信;而 ThreadLocal 是隔離多個線程的數據共享,從根本上就不在多個線程之間共享資源,這樣當然不需要多個線程進行同步了。

(4)使用技巧:需要多個線程之間進行通信,使用同步機制;如果需要隔離多個線程之間的共享衝突,推薦使用 ThreadLocal (線程安全)。

java同步是什麼意思

一般有兩種方法同步方法和同步代碼塊

假設P1、P2是同一個類的不同對象,這個類中定義了以下幾種情況的同步塊或同步方法,P1、P2就都可以調用它們。

1.把synchronized當作函數修飾符時,示例代碼如下:

PublicsynchronizedvoidmethodAAA()

{

//….

}

這也就是同步方法,那這時synchronized鎖定的是哪個對象呢?它鎖定的是調用這個同步方法對象。也就是說,當一個對象P1在不同的線程中執行這個同步方法時,它們之間會形成互斥,達到同步的效果。但是這個對象所屬的Class所產生的另一對象P2卻可以任意調用這個被加了synchronized關鍵字的方法。

上邊的示例代碼等同於如下代碼:

publicvoidmethodAAA()

{

synchronized(this)//(1)

{

//…..

}

}

(1)處的this指的是什麼呢?它指的就是調用這個方法的對象,如P1。可見同步方法實質是將synchronized作用於objectreference。――那個拿到了P1對象鎖的線程,才可以調用P1的同步方法,而對P2而言,P1這個鎖與它毫不相干,程序也可能在這種情形下擺脫同步機制的控制,造成數據混亂:(

2.同步塊,示例代碼如下:

publicvoidmethod3(SomeObjectso)

{

synchronized(so)

{

//…..

}

}

這時,鎖就是so這個對象,誰拿到這個鎖誰就可以運行它所控制的那段代碼。當有一個明確的對象作為鎖時,就可以這樣寫程序,但當沒有明確的對象作為鎖,只是想讓一段代碼同步時,可以創建一個特殊的instance變數(它得是一個對象)來充當鎖:

classFooimplementsRunnable

{

privatebyte[]lock=newbyte[0];//特殊的instance變數

PublicvoidmethodA()

{

synchronized(lock){//…}

}

//…..

}

註:零長度的byte數組對象創建起來將比任何對象都經濟――查看編譯後的位元組碼:生成零長度的byte[]對象只需3條操作碼,而Objectlock=newObject()則需要7行操作碼。

3.將synchronized作用於static函數,示例代碼如下:

ClassFoo

{

publicsynchronizedstaticvoidmethodAAA()//同步的static函數

{

//….

}

publicvoidmethodBBB()

{

synchronized(Foo.class)//classliteral(類名稱字面常量)

}

}

代碼中的methodBBB()方法是把classliteral作為鎖的情況,它和同步的static函數產生的效果是一樣的,取得的鎖很特別,是當前調用這個方法的對象所屬的類(Class,而不再是由這個Class產生的某個具體對象了)。

記得在《EffectiveJava》一書中看到過將Foo.class和P1.getClass()用於作同步鎖還不一樣,不能用P1.getClass()來達到鎖這個Class的目的。P1指的是由Foo類產生的對象。

可以推斷:如果一個類中定義了一個synchronized的static函數A,也定義了一個synchronized的instance函數B,那麼這個類的同一對象Obj在多線程中分別訪問A和B兩個方法時,不會構成同步,因為它們的鎖都不一樣。A方法的鎖是Obj這個對象,而B的鎖是Obj所屬的那個Class。

java 方法同步

1.同步方法 即有synchronized關鍵字修飾的方法。 由於java的每個對象都有一個內置鎖,當用此關鍵字修飾方法時, 內置鎖會保護整個方法。在調用該方法前,需要獲得內置鎖,否則就處於阻塞狀態。 代碼如: public synchronized void save(){} 註: synchronized關鍵字也可以修飾靜態方法,此時如果調用該靜態方法,將會鎖住整個類 2.同步代碼塊 即有synchronized關鍵字修飾的語句塊。 被該關鍵字修飾的語句塊會自動被加上內置鎖,從而實現同步 代碼如: synchronized(object){ } 註:同步是一種高開銷的操作,因此應該盡量減少同步的內容。 通常沒有必要同步整個方法,使用synchronized代碼塊同步關鍵代碼即可。 代碼實例: 複製代碼package com.xhj.thread; /** * 線程同步的運用 * * @author XIEHEJUN * */ public class SynchronizedThread { class Bank { private int account = 100; public int getAccount() { return account; } /** * 用同步方法實現 * * @param money */ public synchronized void save(int money) { account += money; } /** * 用同步代碼塊實現 * * @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)實現線程同步 a.volatile關鍵字為域變數的訪問提供了一種免鎖機制, b.使用volatile修飾域相當於告訴虛擬機該域可能會被其他線程更新, c.因此每次使用該域就要重新計算,而不是使用寄存器中的值 d.volatile不會提供任何原子操作,它也不能用來修飾final類型的變數 例如: 在上面的例子當中,只需在account前面加上volatile修飾,即可實現線程同步。 代碼實例: 複製代碼 //只給出要修改的代碼,其餘代碼與上同 class Bank { //需要同步的變數加上volatile private volatile int account = 100; public int getAccount() { return account; } //這裡不再需要synchronized public void save(int money) { account += money; } }複製代碼 註:多線程中的非同步問題主要出現在對域的讀寫上,如果讓域自身避免這個問題,則就不需要修改操作該域的方法。 用final域,有鎖保護的域和volatile域可以避免非同步的問題。 4.使用重入鎖實現線程同步 在JavaSE5.0中新增了一個java.util.concurrent包來支持同步。 ReentrantLock類是可重入、互斥、實現了Lock介面的鎖, 它與使用synchronized方法和快具有相同的基本行為和語義,並且擴展了其能力 ReenreantLock類的常用方法有: ReentrantLock() : 創建一個ReentrantLock實例 lock() : 獲得鎖 unlock() : 釋放鎖 註:ReentrantLock()還有一個可以創建公平鎖的構造方法,但由於能大幅度降低程序運行效率,不推薦使用 例如: 在上面例子的基礎上,改寫後的代碼為: 代碼實例: 複製代碼//只給出要修改的代碼,其餘代碼與上同 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類,此時要注意及時釋放鎖,否則會出現死鎖,通常在finally代碼釋放鎖 5.使用局部變數實現線程同步 如果使用ThreadLocal管理變數,則每一個使用該變數的線程都獲得該變數的副本, 副本之間相互獨立,這樣每一個線程都可以隨意修改自己的變數副本,而不會對其他線程產生影響。 ThreadLocal 類的常用方法 ThreadLocal() : 創建一個線程本地變數 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.前者採用以”空間換時間”的方法,後者採用以”時間換空間”的方式。

原創文章,作者:JFLC,如若轉載,請註明出處:https://www.506064.com/zh-tw/n/134513.html

(0)
打賞 微信掃一掃 微信掃一掃 支付寶掃一掃 支付寶掃一掃
JFLC的頭像JFLC
上一篇 2024-10-04 00:06
下一篇 2024-10-04 00:06

相關推薦

  • Java JsonPath 效率優化指南

    本篇文章將深入探討Java JsonPath的效率問題,並提供一些優化方案。 一、JsonPath 簡介 JsonPath是一個可用於從JSON數據中獲取信息的庫。它提供了一種DS…

    編程 2025-04-29
  • java client.getacsresponse 編譯報錯解決方法

    java client.getacsresponse 編譯報錯是Java編程過程中常見的錯誤,常見的原因是代碼的語法錯誤、類庫依賴問題和編譯環境的配置問題。下面將從多個方面進行分析…

    編程 2025-04-29
  • Java Bean載入過程

    Java Bean載入過程涉及到類載入器、反射機制和Java虛擬機的執行過程。在本文中,將從這三個方面詳細闡述Java Bean載入的過程。 一、類載入器 類載入器是Java虛擬機…

    編程 2025-04-29
  • Python中new和init的區別

    new和init都是Python中常用的魔法方法,它們分別負責對象的創建和初始化,本文將從多個角度詳細闡述它們的區別。 一、創建對象 new方法是用來創建一個對象的,它是一個類級別…

    編程 2025-04-29
  • Java騰訊雲音視頻對接

    本文旨在從多個方面詳細闡述Java騰訊雲音視頻對接,提供完整的代碼示例。 一、騰訊雲音視頻介紹 騰訊雲音視頻服務(Cloud Tencent Real-Time Communica…

    編程 2025-04-29
  • Java Milvus SearchParam withoutFields用法介紹

    本文將詳細介紹Java Milvus SearchParam withoutFields的相關知識和用法。 一、什麼是Java Milvus SearchParam without…

    編程 2025-04-29
  • Java 8中某一周的周一

    Java 8是Java語言中的一個版本,於2014年3月18日發布。本文將從多個方面對Java 8中某一周的周一進行詳細的闡述。 一、數組處理 Java 8新特性之一是Stream…

    編程 2025-04-29
  • Java判斷字元串是否存在多個

    本文將從以下幾個方面詳細闡述如何使用Java判斷一個字元串中是否存在多個指定字元: 一、字元串遍歷 字元串是Java編程中非常重要的一種數據類型。要判斷字元串中是否存在多個指定字元…

    編程 2025-04-29
  • VSCode為什麼無法運行Java

    解答:VSCode無法運行Java是因為默認情況下,VSCode並沒有集成Java運行環境,需要手動添加Java運行環境或安裝相關插件才能實現Java代碼的編寫、調試和運行。 一、…

    編程 2025-04-29
  • Java任務下發回滾系統的設計與實現

    本文將介紹一個Java任務下發回滾系統的設計與實現。該系統可以用於執行複雜的任務,包括可回滾的任務,及時恢復任務失敗前的狀態。系統使用Java語言進行開發,可以支持多種類型的任務。…

    編程 2025-04-29

發表回復

登錄後才能評論