亚洲中字慕日产2020,大陆极品少妇内射AAAAAA,无码av大香线蕉伊人久久,久久精品国产亚洲av麻豆网站

資訊專欄INFORMATION COLUMN

初識(shí)線程關(guān)鍵字

Michael_Ding / 3244人閱讀

摘要:架構(gòu)師入門(mén)筆記一初識(shí)線程關(guān)鍵字本章節(jié)主要介紹線程的關(guān)鍵字,的含義,使用方法,使用場(chǎng)景,以及注意事項(xiàng)。若次方法也加上了,就必須等待線程執(zhí)行完后,才能調(diào)用關(guān)鍵字不具備關(guān)鍵字的原子性同步其主要作用就是使變量在多個(gè)線程中可見(jiàn)。

架構(gòu)師入門(mén)筆記一 初識(shí)線程關(guān)鍵字

本章節(jié)主要介紹線程的關(guān)鍵字 synchronized,volatile 的含義,使用方法,使用場(chǎng)景,以及注意事項(xiàng)。

線程安全

首先我們要了解線程安全的概念:當(dāng)多個(gè)線程訪問(wèn)某一個(gè)類(對(duì)象或方法)時(shí),這個(gè)類始終都能表現(xiàn)出正確的行為,那么這個(gè)類(對(duì)象或方法)就是線程安全的。
要如何確保類能表現(xiàn)出正確的行為,這就需要關(guān)鍵字出馬!

關(guān)鍵字 synchronized

synchronized 可以在任意對(duì)象及方法上加鎖,而加鎖的這段代碼稱為"互斥區(qū)"或"臨界區(qū)"
其工作原理:當(dāng)一個(gè)線程想要執(zhí)行synchronized修飾的方法,必須經(jīng)過(guò)以下三個(gè)步驟

step1 嘗試獲得鎖

step2 如果拿到鎖,執(zhí)行synchronized代碼體內(nèi)容

step3 如果拿不到鎖,這個(gè)線程就會(huì)不斷地嘗試獲得這把鎖,直到拿到為止。這個(gè)過(guò)程可能是多個(gè)線程同時(shí)去競(jìng)爭(zhēng)這把鎖(鎖競(jìng)爭(zhēng)的問(wèn)題)。

注*(多個(gè)線程執(zhí)行的順序是按照CPU分配的先后順序而定的,而并非代碼執(zhí)行的先后順序)

使用方法介紹:
synchronized 重入
在使用synchronized時(shí),當(dāng)一個(gè)線程得到了一個(gè)對(duì)象的鎖后,再次請(qǐng)求此對(duì)象時(shí)是可以再次得到該對(duì)象的鎖。

public class MySyncReentrant {  
      
    /** 
     * 重入調(diào)用 
     */  
    private synchronized void method1() {  
        System.out.println("^^^^^^^^^^^^^method1");  
        method2();  
    }  
      
    private synchronized void method2() {  
        System.out.println("-----------------------method2");  
        method3();  
    }  
      
    private synchronized void method3() {  
        System.out.println("********************method3");  
    }  
  
    public static void main(String[] args) {  
        final MySyncReentrant mySyncReentrant = new MySyncReentrant();  
        Thread thread = new Thread(new Runnable() {  
            @Override  
            public void run() {  
                mySyncReentrant.method1();  
            }  
        }, "reentrant");  
        thread.start();  
          
        Thread thread2 = new Thread(new Runnable() {  
            @Override  
            public void run() {  
                SunClass sunClass = new SunClass();  
                sunClass.sunMethod();  
            }  
        });  
        thread2.start();  
    }  
    /** 
     * 有父子繼承關(guān)系的類,如果都使用了synchronized關(guān)鍵字,也是線程安全的。 
     */  
    static class FatherClass {  
        public synchronized void fatherMethod(){  
            System.out.println("fatherMethod....");  
        }  
    }  
      
    static class SunClass extends FatherClass{  
        public synchronized void sunMethod() {  
            System.out.println("sunMethod....");  
            this.fatherMethod();  
        }  
    }  
      
}  

synchronized 代碼塊:
如果被修飾的方法執(zhí)行需要很長(zhǎng)時(shí)間,線程之間等待的時(shí)間就會(huì)很長(zhǎng),所以將synchronized 修飾在代碼塊上是可以優(yōu)化執(zhí)行時(shí)間。(這也叫減少鎖的粒度)
synchronized (this) {} , 可以是 this(對(duì)象鎖) class(類鎖) Object lock = new Object(); 任何對(duì)象鎖。

import java.util.concurrent.atomic.AtomicInteger;  
public class CodeBlockLock {  
      
    // 對(duì)象鎖  
    private void thisLock () {  
        synchronized (this) {  
            System.out.println("this 對(duì)象鎖!");  
        }  
    }  
      
    // 類鎖  
    private void classLock () {  
        synchronized (CodeBlockLock.class) {  
            System.out.println("class 類鎖!");  
        }  
    }  
      
    // 任何對(duì)象鎖  
    private Object lock = new Object();  
    private void objectLock () {  
        synchronized (lock) {  
            System.out.println("object 任何對(duì)象鎖!");  
        }  
    }  
      
    // 字符串鎖,注意String常量池的緩存功能  
    private void stringLock () {  
        synchronized ("string") { // new String("string")  
            try {  
                for(int i = 0; i < 3; i++) {  
                    System.out.println("thread : " + Thread.currentThread().getName() + " stringLock !");  
                    Thread.sleep(1000);       
                }  
            } catch (InterruptedException e) {  
                e.printStackTrace();  
            }  
        }  
    }  
      
    // 字符串鎖改變  
    private String strLock = "lock";  
    private void changeStrLock () {  
        synchronized (strLock) {  
            try {  
                System.out.println("thread : " + Thread.currentThread().getName() + " changeLock start !");  
                strLock = "changeLock";  
                Thread.sleep(5000);  
                System.out.println("thread : " + Thread.currentThread().getName() + " changeLock end !");  
            } catch (InterruptedException e) {  
                e.printStackTrace();  
            }  
        }  
    }  
      
    public static void main(String[] args) {  
        final CodeBlockLock codeBlockLock = new CodeBlockLock();  
        Thread thread1 = new Thread(new Runnable() {  
            @Override  
            public void run() {  
                codeBlockLock.thisLock();  
            }  
        });  
        Thread thread2 = new Thread(new Runnable() {  
            @Override  
            public void run() {  
                codeBlockLock.classLock();  
            }  
        });  
        Thread thread3 = new Thread(new Runnable() {  
            @Override  
            public void run() {  
                codeBlockLock.objectLock();  
            }  
        });  
        thread1.start();  
        thread2.start();  
        thread3.start();  
          
        // 如果字符串鎖,用new String("string") t4,t5線程是可以獲取鎖的,如果直接使用"string" ,若鎖不釋放,t5線程一直處理等待中  
        Thread thread4 = new Thread(new Runnable() {  
            @Override  
            public void run() {  
                codeBlockLock.stringLock();  
            }  
        }, "t4");  
        Thread thread5 = new Thread(new Runnable() {  
            @Override  
            public void run() {  
                codeBlockLock.stringLock();  
            }  
        }, "t5");  
        thread4.start();  
        thread5.start();  
          
        try {  
            Thread.sleep(10000);  
        } catch (InterruptedException e) {  
            e.printStackTrace();  
        }  
          
        // 字符串變了,鎖也會(huì)改變,導(dǎo)致t7線程在t6線程未結(jié)束后變開(kāi)始執(zhí)行,但一個(gè)對(duì)象的屬性變了,不影響這個(gè)對(duì)象的鎖。  
        Thread thread6 = new Thread(new Runnable() {  
            @Override  
            public void run() {  
                codeBlockLock.changeStrLock();  
            }  
        }, "t6");  
        Thread thread7 = new Thread(new Runnable() {  
            @Override  
            public void run() {  
                codeBlockLock.changeStrLock();  
            }  
        }, "t7");  
        thread6.start();  
        thread7.start();  
    }  
  
} 

運(yùn)行結(jié)果:

this 對(duì)象鎖!  
class 類鎖!  
object 任何對(duì)象鎖!  
thread : t4 stringLock !  
thread : t4 stringLock !  
thread : t4 stringLock !  
thread : t5 stringLock !  
thread : t5 stringLock !  
thread : t5 stringLock !  
thread : t6 changeLock start !  
thread : t7 changeLock start !  
thread : t6 changeLock end !  
thread : t7 changeLock end !  

注* 給String的常量加鎖,容易會(huì)出現(xiàn)死循環(huán)的情況。 如果加鎖的字符串變了,鎖也會(huì)變。若一個(gè)對(duì)象的屬性變了,是不影響這個(gè)對(duì)象的鎖。static + synchronized 一起使用 是類級(jí)別的鎖
synchronized 異常:
synchronized 遇到異常后,自動(dòng)釋放鎖,讓其他線程調(diào)用。如果第一個(gè)線程在執(zhí)行任務(wù)時(shí),因?yàn)楫惓?dǎo)致業(yè)務(wù)邏輯未能正常執(zhí)行。后續(xù)的線程執(zhí)行的任務(wù)也都是異常的。所以在編寫(xiě)代碼時(shí)一定要考慮周全

同步與異步

同步的概念就是共享,其目標(biāo)就是為了線程安全(線程安全的兩個(gè)特性:原子性和可見(jiàn)性),A線程獲取對(duì)象的鎖,若B線程想要執(zhí)行synchronized方法,就需要等待,這就是同步。
異步的概念就是獨(dú)立,A線程獲取對(duì)象的鎖,若B線程想要執(zhí)行非synchronized方法,是無(wú)需等待的,這就是異步??梢詤⒖糰jax請(qǐng)求。

public class SyncAndAsyn {  
      
    private synchronized void syncMethod() {  
        try {  
            System.out.println(Thread.currentThread().getName() + " synchronized method!");  
            Thread.sleep(4000);  
        } catch (InterruptedException e) {  
            e.printStackTrace();  
        }  
    }  
      
    // 若次方法也加上了 synchronized,就必須等待t1線程執(zhí)行完后,t2才能調(diào)用  
    private void asynMethod() {  
        System.out.println(Thread.currentThread().getName() + " asynchronized method!");  
    }  
      
    public static void main(String[] args) {  
        final SyncAndAsyn syncAndAsyn = new SyncAndAsyn();  
          
        Thread thread1 = new Thread(new Runnable() {  
            @Override  
            public void run() {  
                syncAndAsyn.syncMethod();  
            }  
        }, "t1");  
        Thread thread2 = new Thread(new Runnable() {  
            @Override  
            public void run() {  
                syncAndAsyn.asynMethod();  
            }  
        }, "t2");  
        thread1.start();  
        thread2.start();  
    }  
  
}  
volatile

volatile關(guān)鍵字不具備synchronized關(guān)鍵字的原子性(同步)其主要作用就是使變量在多個(gè)線程中可見(jiàn)。
原理圖:

在java中,每一個(gè)線程都會(huì)有一塊工作內(nèi)存區(qū),其中存放著所有線程共享的主內(nèi)存中的變量值的拷貝。當(dāng)線程執(zhí)行時(shí),他在自己的工作內(nèi)存區(qū)中操作這些變量。
為了存取一個(gè)共享的變量,一個(gè)線程通常先獲取鎖定并去清除它的內(nèi)存工作區(qū),把這些共享變量從所有線程的共享內(nèi)存區(qū)中正確的裝入到他自己的所在的工作內(nèi)存區(qū)中。當(dāng)線程解鎖時(shí)保證該工作內(nèi)存區(qū)中變量的值寫(xiě)回到共享內(nèi)存中。
volatile的作用就是強(qiáng)制線程到主內(nèi)存里面去讀取變量,而不去線程工作內(nèi)存區(qū)里面讀,從而實(shí)現(xiàn)了多個(gè)線程間的變量可見(jiàn)。也就是滿足線程安全的可見(jiàn)性。
可見(jiàn)性:(被volatile修飾的變量,線程執(zhí)行引擎是直接從主內(nèi)存中讀取變量的值)

public class VolatileThread extends Thread{  
      
    // 如果不加 volatile,會(huì)導(dǎo)致 "thread end !" 一直沒(méi)有打印,  
    private volatile boolean flag = true;  
      
    @Override  
    public void run() {  
        System.out.println("thread start !");  
        while (flag) {  
        }  
        System.out.println("thread end !");  
    }  
  
    public static void main(String[] args) {  
        VolatileThread thread = new VolatileThread();  
        thread.start();  
        try { // 等線程啟動(dòng)了,再設(shè)置值  
            Thread.sleep(1000);  
        } catch (InterruptedException e) {  
            e.printStackTrace();  
        }  
        thread.setFlag(false);  
        System.out.println("flag : " + thread.isFlag());  
    }  
      
    public boolean isFlag() {  
        return flag;  
    }  
  
    public void setFlag(boolean flag) {  
        this.flag = flag;  
    }  
  
}  

volatile 不具備原子性:(多線程之間不是同步的,存在線程安全,從下面的例子中可以得知:如果是同步的,最后一次打印絕對(duì)是1000*10 。為了彌補(bǔ)這個(gè)問(wèn)題,可以考慮使用atomic類的系類對(duì)象)

import java.util.concurrent.atomic.AtomicInteger;  
  
/** 
 * volatile關(guān)鍵字不具備synchronized關(guān)鍵字的原子性(同步) 
 */  
public class VolatileNoAtomic extends Thread{  
    // 多次執(zhí)行程序,會(huì)發(fā)現(xiàn)最后打印的結(jié)果不是1000的整數(shù)倍.中途打印不是1000的整數(shù)倍,可能是因?yàn)镾ystem.out打印的延遲造成的  
//  private static volatile int count;   
    private static AtomicInteger count = new AtomicInteger(0); // 不會(huì)出現(xiàn)以上的情況  
    private static void addCount(){  
        for (int i = 0; i < 1000; i++) {  
//          count++ ;  
            count.incrementAndGet();  
        }  
        System.out.println(count);  
    }  
      
    public void run(){  
        addCount();  
    }  
      
    public static void main(String[] args) {  
        VolatileNoAtomic[] arr = new VolatileNoAtomic[10];  
        for (int i = 0; i < 10; i++) {  
            arr[i] = new VolatileNoAtomic();  
        }  
        // 執(zhí)行10個(gè)線程  
        for (int i = 0; i < 10; i++) {  
            arr[i].start();  
        }  
    }  
      
}  

其實(shí)atomic類 并非完美,它也只能保證自己方法是原子性,若要保證多次操作也是原子性,就需要synchronized的幫忙(若不用synchronized修飾,打印的結(jié)果中會(huì)出現(xiàn)非10倍數(shù)的信息,需多次執(zhí)行才能模擬出來(lái))

import java.util.ArrayList;  
import java.util.List;  
import java.util.concurrent.atomic.AtomicInteger;  
  
public class AtomicUse {  
  
    private static AtomicInteger count = new AtomicInteger(0);  
      
    //多個(gè)addAndGet在一個(gè)方法內(nèi)是非原子性的,需要加synchronized進(jìn)行修飾,保證4個(gè)addAndGet整體原子性 .  
    /**synchronized*/  
    public  int multiAdd(){  
            try {  
                Thread.sleep(100);  
            } catch (InterruptedException e) {  
                e.printStackTrace();  
            }  
            count.addAndGet(1);  
            count.addAndGet(2);  
            count.addAndGet(3);  
            count.addAndGet(4); //+10  
            return count.get();  
    }  
      
    public static void main(String[] args) {  
        final AtomicUse au = new AtomicUse();  
        List ts = new ArrayList();  
        for (int i = 0; i < 100; i++) {  
            ts.add(new Thread(new Runnable() {  
                @Override  
                public void run() {  
                    System.out.println(au.multiAdd());  
                }  
            })); // 添加100個(gè)線程  
        }  
        for(Thread t : ts){  
            t.start();  
        }  
          
    }  
}  

以上便是初識(shí)線程關(guān)鍵字的內(nèi)容,方便自己以后查閱,也希望對(duì)讀者有些幫助。

文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請(qǐng)注明本文地址:http://www.ezyhdfw.cn/yun/70526.html

相關(guān)文章

  • 初識(shí)Queue隊(duì)列

    摘要:架構(gòu)師入門(mén)筆記三初識(shí)隊(duì)列和模擬基礎(chǔ)知識(shí)線程通信概念線程是操作系統(tǒng)中獨(dú)立的個(gè)體,但這些個(gè)體如果不經(jīng)過(guò)特殊的處理,就不能成為一個(gè)整體,線程之間的通信就成為整體的必用方法之一。它是一個(gè)基于鏈接節(jié)點(diǎn)的無(wú)界限線程安全隊(duì)列。 架構(gòu)師入門(mén)筆記三 初識(shí)Queue隊(duì)列 wait和notify模擬Queue wait/notify 基礎(chǔ)知識(shí) 線程通信概念:線程是操作系統(tǒng)中獨(dú)立的個(gè)體,但這些個(gè)體如果不經(jīng)過(guò)特...

    Miracle_lihb 評(píng)論0 收藏0
  • 初識(shí)JAVA多線程編程

    摘要:多線程術(shù)語(yǔ)辨析任務(wù)和線程是不同的中類本身不執(zhí)行任何操作它只驅(qū)動(dòng)賦予它的任務(wù)而才是定義任務(wù)的地方創(chuàng)建任務(wù)的方式有兩種實(shí)現(xiàn)接口中的方法查看源碼可以看到只有一個(gè)方法使用直接繼承即可這樣就創(chuàng)建了一個(gè)任務(wù)暗示調(diào)度器該線程可以讓出資源了中實(shí)現(xiàn)方法部分源 java多線程 1. 術(shù)語(yǔ)辨析 任務(wù)和線程是不同的,Java中Thread類本身不執(zhí)行任何操作,它只驅(qū)動(dòng)賦予它的任務(wù),而Runnable才是定義任...

    luzhuqun 評(píng)論0 收藏0
  • PHP下的異步嘗試二:初識(shí)協(xié)程

    摘要:如果僅依靠程序自動(dòng)交出控制的話,那么一些惡意程序?qū)?huì)很容易占用全部時(shí)間而不與其他任務(wù)共享。多個(gè)操作可以在重疊的時(shí)間段內(nèi)進(jìn)行。 PHP下的異步嘗試系列 如果你還不太了解PHP下的生成器,你可以根據(jù)下面目錄翻閱 PHP下的異步嘗試一:初識(shí)生成器 PHP下的異步嘗試二:初識(shí)協(xié)程 PHP下的異步嘗試三:協(xié)程的PHP版thunkify自動(dòng)執(zhí)行器 PHP下的異步嘗試四:PHP版的Promise ...

    MudOnTire 評(píng)論0 收藏0
  • [初識(shí)C++] 何為最:心酸歷史

    摘要:上面需要了解的是這倆個(gè)版本都是破蛹成蝶的版本世界挑戰(zhàn)榜咋才前三還沒(méi)擠進(jìn)去呀,你想想世界上有幾千中編程語(yǔ)言,在其中脫穎出來(lái),可以說(shuō)是天之?huà)勺?,鳳毛麟角了。支持正版圖靈上面買(mǎi)吧,如果沒(méi)錢(qián)買(mǎi)盜版吧學(xué)完以后買(mǎi)本正版支持一下,創(chuàng)作不易是吧 ...

    forrest23 評(píng)論0 收藏0

發(fā)表評(píng)論

0條評(píng)論

最新活動(dòng)
閱讀需要支付1元查看
<