Java線程同步的實現__java

來源:互聯網
上載者:User

線程共用受限資源
1、基本上所有的併發模式在解決線程衝突的時候,都是採用 序列化訪問共用資源的方案,這一位著在給定時刻只允許一個任務訪問共用資源; 這通常是在代碼前加上一條鎖語句實現的,這種機制常常被稱為 互斥量(mutex)

2、隱式加鎖同步使用synchronized關鍵字
1)共用資源一般是以對象形式存在的 記憶體片段,但也可以是檔案、輸入輸出連接埠、印表機; 2)要控制共用資源的訪問, 首先要將其封裝進一個對象然後要將所有訪問該資源的方法(或代碼塊)標記為synchronized;      同時要將該共用域標記為private; 3)範例程式碼
1、對整個方法進行同步class demo{     private int shareResource;     public synchronized void method1(){  shareResource ++;  }     public synchronized void method2(){  shareResource --;  }}2、對方法中需要同步的地方進行同步class demo{     private int shareResource;     public void method1(){          System.out.println("method1 start");          synchronized(this){               shareResource ++;            }           System.out.println("method1 end");      }     public void method2(){          System.out.println("method2 start");          synchronized(this){               shareResource --;           }          System.out.println("method2 end");     }}

4)對於 某個特定的對象來說,其範圍內 所有的synchronized方法共用一個鎖; 5)每個訪問臨界共用資源的方法都必須被同步,否則其他方法會隨意忽視該鎖;

3、顯式加鎖同步:利用Lock進行加鎖
1)java SE5中的java.util.concurrent.Locks 可以顯式地定義互斥機制; 2)範例程式碼
class Demo{     private int shareResource;     private Lock lock = new ReentrantLock();     public int method{          lock.lock();          try{               shareResource ++;               return shareResource;          }finallly{               lock.unlock();          }     }//將同步塊放置在try-finally塊中,return必須在try塊中,以確保unlock不會過早發生,從而將資料暴露給第二個任務;}


3)使用synchronized隱式加鎖的代碼量更少, 通常在一些特殊情況下才會使用Lock對象,如: ①使用synchronized不能嘗試擷取鎖,且最終擷取鎖失敗時只會拋出一個異常,無法進行任何的清除工作; ②嘗試擷取鎖一段時間,然後釋放它;
class Demo{     private Reentrantock lock = new ReentrantLock();     public void method1(){          boolean result = lock.tryLock();   //僅在調用時,lock處於空閑狀態才擷取鎖;          try{               System.out.println(result);          }finally{               if(result)                    lock.unlock();          }     }     public void method2(){          boolean result = false;          try{               result = lock.tryLock(2,TimeUnit.SECONDS);                 //在調用時,lock在2seconds內處於空閑狀態,且線程在這個時間段類沒有被打斷,才擷取鎖;          }catch(InterruptedException e){               System.out.println(result);          }finally{               if(result)                    lock.unlock();          }     }}





4、通過限制1個許可訊號量來類比一個互斥的鎖(訊號量時用來限制訪問共用資源的線程數)
  class Task{     Semaphore semaphore = new Semaphore(1);     public void xMethod(){           try{                 semaphore.acquire();                 statement;           }catch(InterruptedException ex){           }finally{                 semaphore.release();           }     }  }




5※、利用原子類取代synchronized互斥同步
1)原子性原子操作不需要進行同步控制,原子操作時不能被線程調度中斷的操作,一旦操作開始,那麼它一定可以在可能發生的“環境切換”之前執行完畢,可以利用這一點的特定來編寫 無鎖的代碼; 2)原子性可以應用在除了long和double之外的所有基本類型之上的“簡單操作”,對於讀寫除了long和double之外的基本變數這樣的操作,可以保證他們會被當做不可分割的操作來操作記憶體;
3)原子類:Java SE5引入了如AtomicInteger,AtomincLong,AtomicReference等特殊的原子性變數,它們提供以下形式的原子性條件更新操作: 這些類被調整為使用在某些現代處理器上可獲得的,並且在機器層級上的原子性,一般應用在效能調優上;
boolean compareAndSet(expectedValue,updateValue); 當前值==預期值,則以原子方式將該值設定為給定的值 int getAndAdd(int delta);  以原子的形式將給定值與當前值相加 int getAndSet(int delta);  以原子形式將當前值設定為給定值 int get(); void set(int newValue); 如:AtomicInteger i = new AtomicInteger(1024);     i.compareAndSet(1024,2048);   //該操作是安全執行緒的 4)範例程式碼
import java.util.concurrent.atomic.*;class Demo{     private AtomicInteger count = new AtomicInteger(0);     public int getValue(){  return count.get(); }     public void method1(){ count.getAndAdd(20);}     public void method2(){ count.getAndDerement(); //count++}     public void method3(){ count.getAndIncrement(); //count--}      //Test     public static void main(){          Demo demo = new Deme();          ExecutorService exec = Executors.newCachedThreadPool();          exec.execute(new Runnable(){               public void run(){                    while(true){                         demo.method1();                         System.out.println(demo.getValue());                    }               }          });           exec.execute(new Runnable(){               public void run(){                    while(true){                         demo.method2();                         System.out.println(demo.getValue());                    }               }          });           exec.execute(new Runnable(){               public void run(){                    while(true){                         demo.method3();                         System.out..println(demo.getValue());                    }               }          });     }}//對資料進行原子性操作,不用使用synchronized就可以對操作進行同步;




6、臨界區 1)臨界區(critical section)/同步控制塊:有時候只是希望多個線程同時存取方法內部的部分代碼,而不是整個方法,這種方式分離出來的代碼塊就是臨界區; synchronized(syncObject){      statements; } 2)在進入該同步控制塊之前,必須擷取syncObject對象的鎖 ,如果其他線程已經擷取該鎖,那麼要等到該鎖釋放後,才能進入該臨界區; 3)使用同步控制塊取代對整個方法進行同步控制 ,可以使多個任務訪問對象的時間效能得到顯著地提升; 4)synchronized塊必須給定一個在其上進行同步的對象(一般比較合理的使用時synchronized(this)即本對象);      有時必須在另一個對象上同步,此時必須保證所有相關的任務都是在同一個對象上同步的, 此時兩個同步控制塊是相互獨立的,他們不會因為對方而阻塞,樣本:
//解決限制:一個對象只能擷取一個同步鎖————使得兩個任務可以同時進入同一個對象class Demo{     private Object syncObject = new Object();     public synchronized void method1(){          while(true){               println("method1()");               Thread.yield();          }     }     public void method2(){          synchronized(syncObject){               while(true){                    println("method2()");                    Thread.yield();               }          }     }    //Test     public static void main(){          final Demo demo = new Demo();          new Thread(){               public void run(){                    demo.method1();               }          }          demo.method2();     }}




7、執行緒區域儲存ThreadLocal 1)除了以上使用互斥量同步的方法外,放置任務子在共用資源上產生衝突的第二種反方式 :根除對變數的共用; 2)在java中的線程 本地儲存是一種自動化機制可以為使用相同變數的每一個線程建立不同的儲存,可以使用 java.lang.ThreadLocal 來實現; 3)執行個體代碼
class Demo{     private static ThreadLocal<Integer> value = new ThreadLocal<Integer>();     value.set(0);     public static void mian(String[] args){          ExecutorService executor = Executors.newCachedThreadPool();          for(int i=0;i<5;i++){               executor.execute(new Runnable(){                    public void run(){                              value.set(value.get()+i);                         System.out.print(value.get()+",");                    }               });          }          TimeUnit.SECONDS.sleep(3);          executor.shutdown();     }}/*output:     0,1,2,3,4*///只能使用set(),get()來修改和訪問TreadLocal的資料;






聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在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.