java-多線程 | 線程安全和線程同步

線程安全

線程安全就是多線程訪問時,采用了加鎖機制,當一個線程訪問該類的某個數(shù)據(jù)時,進行保護,其他線程不能進行訪問直到該線程讀取完,其他線程才可使用。不會出現(xiàn)數(shù)據(jù)不一致或者數(shù)據(jù)污染。
線程不安全就是不提供數(shù)據(jù)訪問保護,有可能出現(xiàn)多個線程先后更改數(shù)據(jù)造成所得到的數(shù)據(jù)是臟數(shù)據(jù)。

概述

如果你的代碼所在的進程中有多個線程在同時運行,而這些線程可能會同時運行這段代碼。如果每次運行結果和單線程運行的結果是一樣的,而且其他的變量的值也和預期的是一樣的,就是線程安全的。
或者說:一個類或者程序所提供的接口對于線程來說是原子操作或者多個線程之間的切換不會導致該接口的執(zhí)行結果存在二義性,也就是說我們不用考慮同步的問題。
線程安全問題都是由全局變量靜態(tài)變量引起的。
若每個線程中對全局變量、靜態(tài)變量只有讀操作,而無寫操作,一般來說,這個全局變量是線程安全的;若有多個線程同時執(zhí)行寫操作,一般都需要考慮線程同步,否則的話就可能影響線程安全。

如何保證線程安全:

1.把共享的變量數(shù)據(jù)標識為private
2.使用synchronized關鍵字同步方法或代碼。

volidate關鍵字的使用

volatile是一個類型 修飾符 (type specifier)。它是被設計用來修飾被不同線程訪問和修改的 變量 。如果沒有volatile,基本上會導致這樣的結果:要么無法編寫多線程程序,要么 編譯器 失去大量優(yōu)化的機會。

Volidate 和Synchroinzed 區(qū)別

java中使用Volidate變量所需的編碼較少,并且運行時開銷也較少,但是它所能實現(xiàn)的功能也僅是 synchronized 的一部分。Synchronized是對Volidate的基礎上增加了互斥的功能。
1.Volidate:只保證可見性,可以多個線程同時訪問voliadte修飾的變量。
2.Synchroinzed:既保證了可見性又保證了互斥性。同時只能有一個線程去訪問。 volatile 變量可以被看作是一種 “程度較輕的 synchronized”;與 synchronized 塊相比,volatile 與鎖相比,Volatile 變量是一種非常簡單但同時又非常脆弱的同步機制,它在某些情況下將提供優(yōu)于鎖的性能和伸縮性。如果嚴格遵循 volatile 的使用條件 —— 即變量真正獨立于其他變量和自己以前的值 —— 在某些情況下可以使用 volatile 代替 synchronized 來簡化代碼。然而,使用 volatile 的代碼往往比使用鎖的代碼更加容易出錯。
當使用volatile 聲明的變量的值的時候,系統(tǒng)總是重新從它所在的內存讀取數(shù)據(jù),即使它前面的指令剛剛從該處讀取過數(shù)據(jù)。而且讀取的數(shù)據(jù)立刻被保存。

經典賣票的例子

public class Multithread implements Runnable
{

    //總票數(shù)
    private int ticket = 100;

    @Override
    public void run()
    {
        saleTicket();
        try
        {
            Thread.sleep(10);
        }
        catch (InterruptedException e)
        {
            e.printStackTrace();
        }

    }

    public void saleTicket()
    {
        while (true)
        {
            if (ticket > 0)
            {
                System.out.println(Thread.currentThread().getName() + "  正在賣第" + ticket + "張票");
                ticket--;
            }
            else
            {
                System.out.println("余票不足!");
                break;
            }
        }
    }

    public static void main(String[] args)
    {
        Multithread mt = new Multithread();
        new Thread(mt, "窗口1").start();
        new Thread(mt, "窗口2").start();
        new Thread(mt, "窗口3").start();
        new Thread(mt, "窗口4").start();
    }
}

利用Synchroinzed 關鍵字進行同步鎖

public class Multithread implements Runnable
{

    //總票數(shù)
    private int ticket = 100;

    //同步鎖對象
    Object obj = new Object();

    /**
     * 利用synchronized關鍵字對代碼塊進行同步
     * 保證同一時間只有一個線程在操作共享變量 其余線程則等待該線程執(zhí)行完畢后再執(zhí)行
     * obj 對象鎖可以是任意類型
     * 注意: 要保證對象鎖是同一個
     */
    @Override
    public void run()
    {
        saleTicket();
        try
        {
            //線程睡眠10毫秒 每個線程都有執(zhí)行機會
            Thread.sleep(10);
        }
        catch (InterruptedException e)
        {
            e.printStackTrace();
        }

    }

    public void saleTicket()
    {
        while (true)
        {
            synchronized (obj){if (ticket > 0)
            {
                System.out.println(Thread.currentThread().getName() + "  正在賣第" + ticket + "張票");
                ticket--;
            }
            else
            {
                System.out.println("余票不足!");
                break;
            }
            }
        }
    }

    public static void main(String[] args)
    {
        Multithread mt = new Multithread();
        new Thread(mt, "窗口1").start();
        new Thread(mt, "窗口2").start();
        new Thread(mt, "窗口3").start();
        new Thread(mt, "窗口4").start();
    }
}

通過synchronized關鍵字對代碼塊進行同步(加鎖),保證共享的變量同一時間只能有一個線程在操作。其他線程則等待該線程執(zhí)行完畢后在進行操作,這樣就保證了線程的同步和共享數(shù)據(jù)的安全!

注意

synchronized 同步代碼塊的鎖可以是任意類對象(繼承Thread類),這個對象必須是線程共享類(靜態(tài)的)
synchronized 可以加在方法上,如果是靜態(tài)方法synchronized的鎖就是這個類的類對象,如果不是靜態(tài)方法,synchronized 加在對象方法上,這個鎖就是this


(未完待續(xù))

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
【社區(qū)內容提示】社區(qū)部分內容疑似由AI輔助生成,瀏覽時請結合常識與多方信息審慎甄別。
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發(fā)布,文章內容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關閱讀更多精彩內容

  • Java-Review-Note——4.多線程 標簽: JavaStudy PS:本來是分開三篇的,后來想想還是整...
    coder_pig閱讀 1,772評論 2 17
  • Java8張圖 11、字符串不變性 12、equals()方法、hashCode()方法的區(qū)別 13、...
    Miley_MOJIE閱讀 3,899評論 0 11
  • 引用自多線程編程指南應用程序里面多個線程的存在引發(fā)了多個執(zhí)行線程安全訪問資源的潛在問題。兩個線程同時修改同一資源有...
    Mitchell閱讀 2,118評論 1 7
  • 本文出自 Eddy Wiki ,轉載請注明出處:http://eddy.wiki/interview-java.h...
    eddy_wiki閱讀 2,298評論 0 14
  • 一個出租車司機,整日忙于奔波,他說,奔波在路上,踏實。也許我們都是這樣,忙著比閑著踏實,掙錢多少,我們對得起時間和...
    平淡陪伴閱讀 140評論 0 0

友情鏈接更多精彩內容