Java多線程(1)

開啟線程的三種方式合住?

  1. 繼承Thread類宅粥,重寫run(),調(diào)用start;
  2. 實(shí)現(xiàn)Runnable接口偎血,復(fù)寫run(),將Runnable子類對(duì)象傳遞給Thread類對(duì)象华望,調(diào)用start;
  3. 創(chuàng)建FutureTask對(duì)象哟玷,創(chuàng)建Callable子類對(duì)象狮辽。重寫call(相當(dāng)于run)方法一也,將其傳遞給FutureTask對(duì)象(相當(dāng)于一個(gè)Runnable)。創(chuàng)建Thread類對(duì)象喉脖,將FutureTask對(duì)象傳遞給Thread對(duì)象椰苟。調(diào)用start方法開啟線程。這種方式可以獲得線程執(zhí)行完之后的返回值树叽。

run()和start()方法區(qū)別

run()是一個(gè)普通方法舆蝴,多線程中可以多次調(diào)用,start()開啟一個(gè)線程题诵。jvm內(nèi)部機(jī)制規(guī)定在調(diào)用start()開啟線程時(shí)洁仗,會(huì)自動(dòng)調(diào)用run().

如何控制某個(gè)方法允許并發(fā)訪問線程的個(gè)數(shù)?

創(chuàng)建一個(gè)Semaphore對(duì)象性锭,初始化訪問線程的個(gè)數(shù)赠潦,在線程開始時(shí)通過acquire()請(qǐng)求信號(hào),線程完成時(shí)release()釋放信號(hào)即可控制訪問線程的個(gè)數(shù)草冈。

Java中wait和seelp方法的不同

sleep()屬于Thread類中的她奥,wait()屬于Object。
sleep()睡眠時(shí)怎棱,保持對(duì)象鎖哩俭,而wait()釋放對(duì)象鎖。wait()通過notify或notifyAll或指定時(shí)間來喚醒當(dāng)前線程(需要獲得鎖對(duì)象)拳恋,必須放在Snchronized block中凡资,否則會(huì)拋出IllegalMonitorStateException

wait/notify關(guān)鍵字的理解

  • wait( ),notify( )谬运,notifyAll( )屬于Object基礎(chǔ)類隙赁,也就是每個(gè)對(duì)象都有wait( ),notify( )吩谦,notifyAll( ) 的功能鸳谜,因?yàn)槊總€(gè)對(duì)象都有鎖,鎖是每個(gè)對(duì)象的基礎(chǔ)式廷,當(dāng)然操作鎖的方法也是最基礎(chǔ)了咐扭。

  • 當(dāng)需要調(diào)用以上的方法的時(shí)候,一定要對(duì)競(jìng)爭(zhēng)資源進(jìn)行加鎖滑废,如果不加鎖的話蝗肪,則會(huì)報(bào) IllegalMonitorStateException 異常

  • 當(dāng)想要調(diào)用wait( )進(jìn)行線程等待時(shí),必須要取得這個(gè)鎖對(duì)象的控制權(quán)(對(duì)象監(jiān)視器)蠕趁,一般是放到synchronized(obj)代碼中薛闪。

  • 在while循環(huán)里而不是if語句下使用wait,這樣俺陋,會(huì)在線程暫突硌樱恢復(fù)后都檢查wait的條件昙篙,并在條件實(shí)際上并未改變的情況下處理喚醒通知

  • 調(diào)用obj.wait( )釋放了obj的鎖,否則其他線程也無法獲得obj的鎖诱咏,也就無法在synchronized(obj){ obj.notify() } 代碼段內(nèi)喚醒A苔可。

  • notify( )方法只會(huì)通知等待隊(duì)列中的第一個(gè)相關(guān)線程(不會(huì)通知優(yōu)先級(jí)比較高的線程)

  • notifyAll( )通知所有等待該競(jìng)爭(zhēng)資源的線程(也不會(huì)按照線程的優(yōu)先級(jí)來執(zhí)行)

  • 假設(shè)有三個(gè)線程執(zhí)行了obj.wait( ),那么obj.notifyAll( )則能全部喚醒tread1袋狞,thread2焚辅,thread3,但是要繼續(xù)執(zhí)行obj.wait()的下一條語句苟鸯,必須獲得obj鎖同蜻,因此,tread1早处,thread2湾蔓,thread3只有一個(gè)有機(jī)會(huì)獲得鎖繼續(xù)執(zhí)行,例如tread1陕赃,其余的需要等待thread1釋放obj鎖之后才能繼續(xù)執(zhí)行卵蛉。

  • 當(dāng)調(diào)用obj.notify/notifyAll后,調(diào)用線程依舊持有obj鎖么库,因此,thread1甘有,thread2诉儒,thread3雖被喚醒,但是仍無法獲得obj鎖亏掀。直到調(diào)用線程退出synchronized塊忱反,釋放obj鎖后,thread1滤愕,thread2温算,thread3中的一個(gè)才有機(jī)會(huì)獲得鎖繼續(xù)執(zhí)行。

什么導(dǎo)致線程阻塞间影?

阻塞狀態(tài)的特點(diǎn)是:該線程放棄CPU的使用注竿,暫停運(yùn)行,等待阻塞原因消除以后才能恢復(fù)運(yùn)行魂贬」睿或者被其他線程中斷退出阻塞狀態(tài),同時(shí)會(huì)拋出InterruptedException付燥。
導(dǎo)致阻塞的原因有:

  • sleep()進(jìn)入睡眠狀態(tài)宣谈;
  • 線程執(zhí)行一段同步代碼,未獲得相關(guān)同步鎖键科,進(jìn)入阻塞狀態(tài)闻丑;
  • 線程調(diào)用對(duì)象的wait方法漩怎,等待其他線程執(zhí)行notify()、notifyAll();
  • 線程執(zhí)行某些IO操作嗦嗡,因?yàn)榈却嚓P(guān)的資源而進(jìn)入阻塞狀態(tài)勋锤,比如System. in。

線程如何關(guān)閉酸钦?

  1. 使用stop()方法強(qiáng)行終止線程怪得,不推薦,可能發(fā)生不可預(yù)料的結(jié)果卑硫;
  2. 使用退出標(biāo)識(shí)徒恋,使線程正常退出;
public class ThreadSafe extends Thread {
    public volatile boolean exit = false; 
        public void run() { 
        while (!exit){
            //do something
        }
    } 
}

定義了一個(gè)退出標(biāo)志exit欢伏,當(dāng)exit為true時(shí)入挣,while循環(huán)退出,exit的默認(rèn)值為false.在定義exit時(shí)硝拧,使用了一個(gè)Java關(guān)鍵字volatile径筏,這個(gè)關(guān)鍵字的目的是使exit同步,也就是說在同一時(shí)刻只能由一個(gè)線程來修改exit的值.

  1. 使用interrupt方法中斷線程障陶。
Thread thread = new Thread(new Runnable() {
    @Override
    public void run() {
        /*
         * 在這里為一個(gè)循環(huán)滋恬,條件是判斷線程的中斷標(biāo)志位是否中斷
         */
        while (true&&(!Thread.currentThread().isInterrupted())) {
            try {
                Log.i("tag","線程運(yùn)行中"+Thread.currentThread().getId());
                // 每執(zhí)行一次暫停40毫秒
                //當(dāng)sleep方法拋出InterruptedException  中斷狀態(tài)也會(huì)被清掉
                Thread.sleep(40);
            } catch (InterruptedException e) {
                e.printStackTrace();
                //如果拋出異常則再次設(shè)置中斷請(qǐng)求
                Thread.currentThread().interrupt();
            }
        }
    }
});
thread.start();
//觸發(fā)條件設(shè)置中斷
thread.interrupt();

java中同步的幾種方式

  1. 同步方法
  2. 同步代碼塊
  3. 特殊域變量,volatile:
  • 為變量的訪問提供了一種免鎖機(jī)制抱究;
  • 告訴jvm該域可能被其他線程更新恢氯;
  • 每次使用都要重新計(jì)算,而不是使用寄存器里的值鼓寺;
  • 不會(huì)提供任何原子操作勋拟,不能修飾final類型變量。
  1. 使用局部變量ThreadLocal實(shí)現(xiàn)
    使用局部變量實(shí)現(xiàn)線程同步妈候,如果使用ThreadLocal管理變量敢靡,則每一個(gè)使用該變量的線程都獲得該變量的副本,副本之間相互獨(dú)立苦银,這樣每一個(gè)線程都可以隨意修改自己的變量副本啸胧,而不會(huì)對(duì)其他線程產(chǎn)生影響。

注:ThreadLocal與同步機(jī)制

  • ThreadLocal與同步機(jī)制都是為了解決多線程中相同變量的訪問沖突問題墓毒。
  • 前者采用以”空間換時(shí)間”的方法吓揪,后者采用以”時(shí)間換空間”的方式
public class Bank{
    //使用ThreadLocal類管理共享變量account
    private static ThreadLocal<Integer> account = new ThreadLocal<Integer>(){
        @Override
        protected Integer initialValue(){
            return 100;
        }
    };
    public void save(int money){
        account.set(account.get()+money);
    }
    public int getAccount(){
        return account.get();
    }
}
  1. 使用重入鎖ReentrantLock
class Bank {
    private int account = 100;
    //需要聲明這個(gè)鎖
    private Lock lock = new ReentrantLock();
    public int getAccount() {
        return account;
    }
    //這里不再需要synchronized 
    public void save(int money) {
        lock.lock();
        try{
            account += money;
        }finally{
            lock.unlock();
        }

    }
}
  1. 使用原子變量實(shí)現(xiàn)線程同步。如AtomicInteger所计,需要線程同步的根本原因就是因?yàn)樽兞康牟僮鞑皇窃有缘?/li>

如何保證線程安全柠辞?如何實(shí)現(xiàn)線程同步?

線程同步主胧,同上叭首。

兩個(gè)進(jìn)程同時(shí)要求寫或者讀习勤,能不能實(shí)現(xiàn)?如何防止進(jìn)程的同步焙格?

  1. 允許多個(gè)讀者同時(shí)執(zhí)行讀操作图毕;
  2. 不允許讀者、寫者同時(shí)操作眷唉;
  3. 不允許多個(gè)寫者同時(shí)操作予颤。

java.util.concurrent.locks.ReadWriteLock;
java.util.concurrent.locks.ReentrantReadWriteLock;

控制訪的數(shù)量即可。Java并發(fā)庫的Semaphore可以完成信號(hào)量的控制冬阳,Semaphore可以控制某個(gè)資源可被同時(shí)訪問的數(shù)量蛤虐,通過acquire()獲取一個(gè)許可,如果沒有就等待肝陪,而release()釋放一個(gè)許可驳庭。

線程間操作List

1使用Collections.synchronizedList()構(gòu)建List;2操作list的方法使用同步鎖。
為何會(huì)兩者都用氯窍,因?yàn)镃ollections.synchronizedList()構(gòu)建的list只針對(duì)list的add(obj)饲常、poll(obj)等方法做同步,在多線程中直接使用方法會(huì)同步,但是在操作list時(shí)狼讨,add(obj)贝淤、poll(obj)方法之前不能保證obj是否被其他線程操作過。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末政供,一起剝皮案震驚了整個(gè)濱河市霹娄,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌鲫骗,老刑警劉巖,帶你破解...
    沈念sama閱讀 212,454評(píng)論 6 493
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件踩晶,死亡現(xiàn)場(chǎng)離奇詭異执泰,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)渡蜻,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,553評(píng)論 3 385
  • 文/潘曉璐 我一進(jìn)店門术吝,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人茸苇,你說我怎么就攤上這事排苍。” “怎么了学密?”我有些...
    開封第一講書人閱讀 157,921評(píng)論 0 348
  • 文/不壞的土叔 我叫張陵淘衙,是天一觀的道長(zhǎng)。 經(jīng)常有香客問我腻暮,道長(zhǎng)彤守,這世上最難降的妖魔是什么毯侦? 我笑而不...
    開封第一講書人閱讀 56,648評(píng)論 1 284
  • 正文 為了忘掉前任,我火速辦了婚禮具垫,結(jié)果婚禮上侈离,老公的妹妹穿的比我還像新娘。我一直安慰自己筝蚕,他們只是感情好卦碾,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,770評(píng)論 6 386
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著起宽,像睡著了一般洲胖。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上燎含,一...
    開封第一講書人閱讀 49,950評(píng)論 1 291
  • 那天宾濒,我揣著相機(jī)與錄音,去河邊找鬼屏箍。 笑死绘梦,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的赴魁。 我是一名探鬼主播卸奉,決...
    沈念sama閱讀 39,090評(píng)論 3 410
  • 文/蒼蘭香墨 我猛地睜開眼,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼颖御!你這毒婦竟也來了榄棵?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 37,817評(píng)論 0 268
  • 序言:老撾萬榮一對(duì)情侶失蹤潘拱,失蹤者是張志新(化名)和其女友劉穎疹鳄,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體芦岂,經(jīng)...
    沈念sama閱讀 44,275評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡瘪弓,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,592評(píng)論 2 327
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了禽最。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片腺怯。...
    茶點(diǎn)故事閱讀 38,724評(píng)論 1 341
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖川无,靈堂內(nèi)的尸體忽然破棺而出呛占,到底是詐尸還是另有隱情,我是刑警寧澤懦趋,帶...
    沈念sama閱讀 34,409評(píng)論 4 333
  • 正文 年R本政府宣布晾虑,位于F島的核電站,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏走贪。R本人自食惡果不足惜佛猛,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 40,052評(píng)論 3 316
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望坠狡。 院中可真熱鬧继找,春花似錦、人聲如沸逃沿。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,815評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽凯亮。三九已至边臼,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間假消,已是汗流浹背柠并。 一陣腳步聲響...
    開封第一講書人閱讀 32,043評(píng)論 1 266
  • 我被黑心中介騙來泰國(guó)打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留富拗,地道東北人臼予。 一個(gè)月前我還...
    沈念sama閱讀 46,503評(píng)論 2 361
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像啃沪,于是被迫代替她去往敵國(guó)和親粘拾。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,627評(píng)論 2 350

推薦閱讀更多精彩內(nèi)容

  • 該文章轉(zhuǎn)自:http://blog.csdn.net/evankaka/article/details/44153...
    加來依藍(lán)閱讀 7,337評(píng)論 3 87
  • 本文主要講了java中多線程的使用方法创千、線程同步缰雇、線程數(shù)據(jù)傳遞、線程狀態(tài)及相應(yīng)的一些線程函數(shù)用法追驴、概述等械哟。 首先講...
    李欣陽閱讀 2,444評(píng)論 1 15
  • Java多線程學(xué)習(xí) [-] 一擴(kuò)展javalangThread類 二實(shí)現(xiàn)javalangRunnable接口 三T...
    影馳閱讀 2,952評(píng)論 1 18
  • 本文出自 Eddy Wiki ,轉(zhuǎn)載請(qǐng)注明出處:http://eddy.wiki/interview-java.h...
    eddy_wiki閱讀 2,078評(píng)論 0 14
  • 怎么判斷git是否安裝成功 git --version 只要能打印出版本號(hào)殿雪,就代表git安裝成功戒良; windows...
    _陽光很暖_閱讀 202評(píng)論 0 0