一、各個線程是經過競爭CPU時間而得到運行機會的
二、各線程何時獲得CPU時間,佔用多久,是不可預測的
三、一個正在運行着的線程在什麼地方被暫停是不肯定的多線程
爲了解決上述問題,確保共享對象在同一時間只容許被一個線程訪問,即線程同步,可使用synchronized和lock來實現。ide
一、修飾一個代碼塊,被修飾的代碼塊稱爲同步代碼塊,做用範圍是大括號{}括起來的代碼;
二、修飾一個方法,被修飾的方法稱爲同步方法,其做用範圍是整個方法;
三、修飾一個靜態方法,做用範圍是整個靜態方法;
例程(銀行存取款)測試
package com.imooc.bank; public class Bank { private String account;//帳號 private int balance;//帳戶餘額 public Bank(String account,int balane){ this.account=account; this.balance=balane; } public String getAccount() { return account; } public void setAccount(String account) { this.account = account; } public int getBalance() { return balance; } public void setBalance(int balance) { this.balance = balance; } @Override public String toString() { return "Bank[帳號:"+account+",餘額:"+balance+"]"; } //存款 public synchronized void saveAccount(){ //獲取當前的帳戶餘額 int balance=getBalance(); try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } //修改金額,存100元 balance+=100; //修改帳餘額 setBalance(balance); //輸出存款後的帳戶餘額 System.out.println("存款後的帳戶餘額爲:"+balance); } public void drawAccount(){ synchronized (this){ //得到當前帳戶餘額 int balance=getBalance(); balance=balance-200; try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } setBalance(balance); System.out.println("取款後的帳戶餘額:"+balance); } } }
package com.imooc.bank; public class DrawAccount implements Runnable{ Bank bank; public DrawAccount(Bank bank){ this.bank=bank; } @Override public void run() { bank.drawAccount(); } }
package com.imooc.bank; public class SaveAccount implements Runnable{ Bank bank; public SaveAccount(Bank bank){ this.bank=bank; } @Override public void run() { bank.saveAccount(); } }
package com.imooc.bank; public class Test { public static void main(String[] args) { //建立帳戶,給定餘額爲10000 Bank bank=new Bank("1001",1000); //建立線程對象 SaveAccount sa=new SaveAccount(bank); DrawAccount da=new DrawAccount(bank); Thread save=new Thread(sa); Thread draw=new Thread(da); save.start(); draw.start(); try { draw.join(); save.join(); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(bank); } }
通過測試,當不加入synchronized實現線程同步時,存款取款的帳戶餘額會發生錯誤,
這裏使用線程延時模擬了線程被打斷的狀況,當存款沒徹底進行完時打斷了此線程進行取款
此時取款後的餘額不正確。
this
當加入了線程同步後,此問題獲得瞭解決。
線程
一、synchroized同步的時候,其中一條線程用完會自動釋放鎖,而Lock須要手動釋放,若是不手動釋放,可能形成死鎖
二、使用synchronized若是其中一個線程不釋放鎖,那麼其餘須要獲取鎖的線程會一直等待下取,直到使用完釋放或者出現異常,
而Lock可使用響應中斷或者使用規定等待時間的鎖
三、synchronized沒法得知是否獲取到鎖,而Lock能夠作到
四、用ReadWriteLock能夠提升多個線程進行讀操做的笑了code
lock簡單的使用方法對象
//建立lock對象 Lock lock=new ReentrantLock(); //手動加鎖 lock.lock(); try{ // 處理 }catch(Exception ex){ // 捕獲異常 }finally{ // 釋放鎖 lock.unlock(); }