Java線程同步詳解

1、多線程運行問題

一、各個線程是經過競爭CPU時間而得到運行機會的
二、各線程何時獲得CPU時間,佔用多久,是不可預測的
三、一個正在運行着的線程在什麼地方被暫停是不肯定的多線程

2、線程同步

爲了解決上述問題,確保共享對象在同一時間只容許被一個線程訪問,即線程同步,可使用synchronized和lock來實現。ide

3、synchronized的使用方式

一、修飾一個代碼塊,被修飾的代碼塊稱爲同步代碼塊,做用範圍是大括號{}括起來的代碼;
二、修飾一個方法,被修飾的方法稱爲同步方法,其做用範圍是整個方法;
三、修飾一個靜態方法,做用範圍是整個靜態方法;

例程(銀行存取款)測試

Class Bank

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);
        }
    }
}

Class DrawAccount 取款

package com.imooc.bank;

public class DrawAccount implements Runnable{
    Bank bank;
    public DrawAccount(Bank bank){
        this.bank=bank;
    }
    @Override
    public void run() {
        bank.drawAccount();
    }
}

Class SaveAccount 存款

package com.imooc.bank;

public class SaveAccount implements Runnable{

    Bank bank;
    public SaveAccount(Bank bank){
        this.bank=bank;
    }
    @Override
    public void run() {
        bank.saveAccount();
    }
}

Class Test 測試類

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

當加入了線程同步後,此問題獲得瞭解決。
線程

lock的使用方式

一、synchroized同步的時候,其中一條線程用完會自動釋放鎖,而Lock須要手動釋放,若是不手動釋放,可能形成死鎖
二、使用synchronized若是其中一個線程不釋放鎖,那麼其餘須要獲取鎖的線程會一直等待下取,直到使用完釋放或者出現異常,
而Lock可使用響應中斷或者使用規定等待時間的鎖
三、synchronized沒法得知是否獲取到鎖,而Lock能夠作到
四、用ReadWriteLock能夠提升多個線程進行讀操做的笑了code

lock簡單的使用方法對象

//建立lock對象
Lock lock=new ReentrantLock();
//手動加鎖
lock.lock();
 try{
    // 處理
 }catch(Exception ex){
     // 捕獲異常
}finally{
     // 釋放鎖
     lock.unlock();   
 }
相關文章
相關標籤/搜索