Java多線程的幾個常用關鍵字


一、同步(synchronized)和異步(asynchronized)

  1、同步(synchronized)簡單說可以理解為共享的意思,如果資源不是共享的,就沒必要進行同步。設置共享資源為同步的話,可以避免一些臟讀情況。

  2、異步(asynchronized)簡單說可以理解為獨立不受到其他任何制約。

舉個例子:

線程1調用了帶有synchronized關鍵字的方法methodA,線程2調用了異步方法methodB,出現的現象是同時控制台輸出 t1,t2。

package com.ietree.multithread.sync;

/**
 * 多線程之對象同步鎖和異步鎖Demo
 *
 * @author ietree
 */
public class SynAndAsynDemo {

    public static void main(String[] args) {
        
        final SynAndAsynDemo mo = new SynAndAsynDemo();
        
        Thread t1 = new Thread(new Runnable() {
            @Override
            public void run() {
                mo.methodA();
            }
        },"t1");
        
        Thread t2 = new Thread(new Runnable() {
            @Override
            public void run() {
                mo.methodB();
            }
        },"t2");
        
        t1.start();
        t2.start();
    }
    
    // 方法A
    public synchronized void methodA(){
        try {
            System.out.println(Thread.currentThread().getName());
            // 休眠4秒
            Thread.sleep(4000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
    
    // 方法B
    public void methodB(){
        System.out.println(Thread.currentThread().getName());
    }
    
}

線程1調用了帶有synchronized關鍵字的方法methodA,線程2調用了帶有synchronized關鍵字的方法methodB,出現的現象是首先輸出t1,等待4秒之后再輸出t2。

package com.ietree.multithread.sync;

/**
 * 多線程之對象同步鎖和異步鎖Demo
 *
 * @author ietree
 */
public class SynAndAsynDemo {

    public static void main(String[] args) {
        
        final SynAndAsynDemo mo = new SynAndAsynDemo();
        
        Thread t1 = new Thread(new Runnable() {
            @Override
            public void run() {
                mo.methodA();
            }
        },"t1");
        
        Thread t2 = new Thread(new Runnable() {
            @Override
            public void run() {
                mo.methodB();
            }
        },"t2");
        
        t1.start();
        t2.start();
    }
    
    // 方法A
    public synchronized void methodA(){
        try {
            System.out.println(Thread.currentThread().getName());
            // 休眠4秒
            Thread.sleep(4000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
    
    // 方法B
    public synchronized void methodB(){
        System.out.println(Thread.currentThread().getName());
    }
    
}

結論:

在第一段代碼中t1線程先持有object對象的Lock鎖,t2線程可以以異步的方式調用對象中的非synchronized修飾的方法,所以同時輸出;

在第二段代碼中t1線程先持有object對象的Lock鎖,t2線程如果在這個時候調用對象中的同步(synchronized)方法則需等待,也就是同步。

二、volatile

作用:volatile關鍵字的作用是:使變量在多個線程間可見(具有可見性),但是僅靠volatile是不能保證線程的安全性,volatile關鍵字不具備synchronized關鍵字的原子性。

Demo1:

package com.ietree.multithread.sync;

public class RunThread extends Thread {
    // volatile
    private boolean isRunning = true;

    private void setRunning(boolean isRunning) {
        this.isRunning = isRunning;
    }

    public void run() {
        System.out.println("進入run方法..");
        int i = 0;
        while (isRunning == true) {
            // ..
        }
        System.out.println("線程停止");
    }

    public static void main(String[] args) throws InterruptedException {
        RunThread rt = new RunThread();
        rt.start();
        Thread.sleep(1000);
        rt.setRunning(false);
        System.out.println("isRunning的值已經被設置了false");
    }
}

程序輸出:

進入run方法..
isRunning的值已經被設置了false

之后進入死循環

Demo2:

package com.ietree.multithread.sync;

public class RunThread extends Thread {
    // volatile
    private volatile boolean isRunning = true;

    private void setRunning(boolean isRunning) {
        this.isRunning = isRunning;
    }

    public void run() {
        System.out.println("進入run方法..");
        int i = 0;
        while (isRunning == true) {
            // ..
        }
        System.out.println("線程停止");
    }

    public static void main(String[] args) throws InterruptedException {
        RunThread rt = new RunThread();
        rt.start();
        Thread.sleep(1000);
        rt.setRunning(false);
        System.out.println("isRunning的值已經被設置了false");
    }
}

程序輸出:

isRunning的值已經被設置了false
線程停止

總結:當多個線程之間需要根據某個條件確定 哪個線程可以執行時,要確保這個條件在 線程之間是可見的。因此,可以用volatile修飾。

volatile 與 synchronized 的比較:

①volatile輕量級,只能修飾變量。synchronized重量級,還可修飾方法

②volatile只能保證數據的可見性,不能用來同步,因為多個線程並發訪問volatile修飾的變量不會阻塞。

synchronized不僅保證可見性,而且還保證原子性,因為,只有獲得了鎖的線程才能進入臨界區,從而保證臨界區中的所有語句都全部執行。多個線程爭搶synchronized鎖對象時,會出現阻塞。

 

線程安全性包括兩個方面,①可見性。②原子性。

從上面自增的例子中可以看出:僅僅使用volatile並不能保證線程安全性。而synchronized則可實現線程的安全性。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM