JAVA面試匯總(二)多線程(六)

JAVA多線程內(nèi)容比較多抓韩,今天寫完了第六篇,后邊還有七(肯定最后一篇了)连茧。

  1. 如何保證多線程讀寫文件的安全核蘸?
    (1)讀寫互斥,寫讀互斥梅屉,寫寫互斥值纱,只有讀讀相容(可以異步)
    (2)FileInputStream、FileOutputStream坯汤、RandomAccessFile均可得到FileChannel對(duì)象
    (3)FileChannel通過(guò)獨(dú)占鎖tryLock()鎖定文件虐唠,用于寫文件。
    (4)FileChannel的tryLock(0, Long.MAX_VALUE, true)是非阻塞的惰聂,是共享鎖疆偿,能被多個(gè)線程同時(shí)持有,它能禁止其他線程獲取獨(dú)占鎖(防止寫進(jìn)程進(jìn)來(lái)寫文件)搓幌,可用于讀文件杆故。
    (5)FileChannel的lock()是阻塞的,在文件被鎖定的情況下溉愁,會(huì)保持阻塞处铛,直到獲得該鎖為止,實(shí)際上這個(gè)可以用作喝tryLock一樣的情況,用于寫文件撤蟆。
//一般用這種方式奕塑,來(lái)循環(huán)獲取鎖,獲取到鎖之后開(kāi)始寫操作家肯。
File file;
try {
    file = FileUtils.createFile(pathFile);
    } catch (IOException e) {
        e.printStackTrace();
        ioListener.onFail("文件創(chuàng)建失敗龄砰,請(qǐng)檢查路徑是否合法以及讀寫權(quán)限");
        return;
}
FileOutputStream fileOutputStream = new FileOutputStream(file);
FileChannel fileChannel = fileOutputStream.getChannel();
//文件鎖
FileLock fileLock = null;
while (true) {
     try {
         fileLock = fileChannel.tryLock(0, Long.MAX_VALUE, true);//共享鎖
         break;
     } catch (Exception e) {
         System.out.println("有其他線程正在操作該文件,當(dāng)前線程" + Thread.currentThread().getName());
     }
}
  1. Java中的ReadWriteLock是什么讨衣?
    (1)ReetrantReadWriteLock管理一組鎖换棚,一個(gè)是只讀的鎖,一個(gè)是寫鎖反镇。
    (2)讀鎖使用共享模式固蚤;寫鎖使用獨(dú)占模式;讀鎖可以在沒(méi)有寫鎖的時(shí)候被多個(gè)線程同時(shí)持有愿险,寫鎖是獨(dú)占的
import java.util.concurrent.locks.ReentrantReadWriteLock;

public class ReentrantReadWriteLockTest {
    //默認(rèn)是非公平鎖
//    static ReentrantReadWriteLock rtLock = new ReentrantReadWriteLock();
    //手工設(shè)置為公平鎖
    static ReentrantReadWriteLock rtLock = new ReentrantReadWriteLock(true);
    public static void main(String[] args) {
        for (int i = 0; i < 10; i++) {
//            new Thread(new RunnableDowngradeLock()).start();
            new Thread(new RunnableUpgradeLock()).start();
        }
    }
    //ReentrantReadWriteLock支持鎖降級(jí)颇蜡,但是一定記得顯示的把兩個(gè)鎖都釋放
    static class RunnableUpgradeLock implements Runnable{
        @Override
        public void run() {
            try {
                //先獲取寫鎖
                rtLock.writeLock().lock();
                System.out.println(Thread.currentThread().getName() + " get writeLock");
                //再獲取讀鎖,這種明顯是降級(jí)辆亏,鎖降級(jí)
                rtLock.readLock().lock();
                System.out.println(Thread.currentThread().getName() + " get read lock");
                System.out.println(Thread.currentThread().getName() + " isWriteLocked "+ rtLock.isWriteLocked());
                System.out.println(Thread.currentThread().getName() + " isFair "+ rtLock.isFair());
            }finally {
                rtLock.writeLock().unlock();
                rtLock.readLock().unlock();
            }
        }
    }
    //ReentrantReadWriteLock不支持鎖升級(jí)风秤,下面這個(gè)執(zhí)行會(huì)死鎖
    static class RunnableDowngradeLock implements Runnable{
        @Override
        public void run() {
            try {
                //先獲取讀鎖
                rtLock.readLock().lock();
                System.out.println(Thread.currentThread().getName() + " get read lock");
                //再獲取寫鎖,這種明顯是升級(jí)了扮叨,鎖升級(jí)
                rtLock.writeLock().lock();
                System.out.println(Thread.currentThread().getName() + " get writeLock");
            }finally {
                rtLock.writeLock().unlock();
                rtLock.readLock().unlock();
            }
        }
    }
}
  1. lock原理
    (1)Lock接口就這么幾個(gè)方法
//嘗試獲取鎖缤弦,獲取成功則返回,否則阻塞當(dāng)前線程
void lock()
//嘗試獲取鎖彻磁,線程在成功獲取鎖之前被中斷碍沐,則放棄獲取鎖,拋出異常 
void lockInterruptibly()
//嘗試獲取鎖衷蜓,獲取鎖成功則返回true累提,否則返回false 
boolean tryLock();
//嘗試獲取鎖,若在規(guī)定時(shí)間內(nèi)獲取到鎖磁浇,則返回true斋陪,否則返回false,未獲取鎖之前被中斷置吓,則拋出異常 
boolean tryLock(long time, TimeUnit unit)
//釋放鎖
void unlock()
//返回當(dāng)前鎖的條件變量无虚,通過(guò)條件變量可以實(shí)現(xiàn)類似notify和wait的功能,一個(gè)鎖可以有多個(gè)條件變量
Condition newCondition()

(2)一定有一個(gè)變量是表示(鎖)狀態(tài)的變量(假設(shè)0表示沒(méi)有線程獲取鎖衍锚,1表示已有線程占有鎖),該變量必須聲明為voaltile類型(任何線程過(guò)來(lái)友题,都要直接從內(nèi)存讀取鎖鎖狀態(tài),不可能從緩存却髦省);
(3)鎖操作步驟:1>先獲取鎖狀態(tài)度宦,如果狀態(tài)時(shí)0未鎖定時(shí)候踢匣,修改鎖狀態(tài)為1,返回鎖定成功斗埂;2>如果時(shí)1已鎖定符糊,進(jìn)入等待隊(duì)列,將自身阻塞呛凶,等待鎖變?yōu)?未鎖定的喚醒該線程,然后執(zhí)行第一步行贪;3>修改鎖狀態(tài)時(shí)漾稀,有可能失敗,搶占式的建瘫,只有第一個(gè)修改的能成功崭捍,后邊的線程修改都失敗,同樣進(jìn)入等待隊(duì)列啰脚,將自身阻塞殷蛇,等待鎖變?yōu)?時(shí)喚醒該線程,然后執(zhí)行第一步
(4)解除鎖操作步驟:1>修改鎖狀態(tài)橄浓,將1變?yōu)?粒梦,然后通知等待隊(duì)列的第一個(gè)線程(如果是公平鎖的話,第一個(gè)等待的)荸实,釋放完成匀们;2>被喚醒的鎖,執(zhí)行上面的所操作步驟准给。3>如果鎖是已經(jīng)被釋放了泄朴,還來(lái)解除鎖操作,這個(gè)時(shí)候直接拋異常失敗露氮。
(5)公平鎖實(shí)現(xiàn):鎖操作時(shí)祖灰,判斷隊(duì)列是否存在等待的線程,1>如果有畔规,就把自己加入隊(duì)列局扶,然后將自身阻塞;2>如果沒(méi)有等待的線程,執(zhí)行所操作步驟第一步油讯。3>隊(duì)列按照先入先出操作详民,所以喚醒的一定是先進(jìn)入隊(duì)列的線程
(6)非公平鎖實(shí)現(xiàn):實(shí)際上就是是否可以插入到隊(duì)列前面,第一個(gè)被喚醒一定是隊(duì)列頭的等待線程陌兑,哪個(gè)線程搶占了隊(duì)列頭沈跨,誰(shuí)就是第一個(gè)。
(7)Condition接口兔综,實(shí)際上就是維護(hù)的等待隊(duì)列饿凛,先進(jìn)先出隊(duì)列

  1. ReentrantLock的內(nèi)部實(shí)現(xiàn)
    (1)其實(shí)上面Lock已經(jīng)說(shuō)的差不多了
    (2)內(nèi)部有抽象類Sync繼承了AbstractQueuedSynchronizer狞玛。Sync有兩個(gè)子類,一個(gè)FairSync另一個(gè)NonfairSync(ReentrantLock默認(rèn)就是非公平鎖)涧窒。
    (3)這個(gè)比Lock多了acquire和tryAcquire的方法心肪,還有tryRelease/getOwner/getHoldCount/isLocked等方法。
    (4)tryAcquire方法分為公平鎖/非公平鎖的纠吴,公平鎖:如果鎖狀態(tài)為0且等待隊(duì)列沒(méi)有等待的線程硬鞍,則通過(guò)cas方式設(shè)置鎖狀態(tài)為1,設(shè)置擁有鎖的線程為自己戴已;如果鎖狀態(tài)大于1固该,判斷擁有鎖的是不是自己,是自己則將狀態(tài)改為加1糖儡,返回成功伐坏,如果擁有鎖的不是自己,返回失敗握联。非公平鎖:如果鎖狀態(tài)為0桦沉,就通過(guò)cas方式搶占鎖,搶占成功設(shè)置狀態(tài)金闽,設(shè)置擁有鎖的線程為自己纯露,如果鎖狀態(tài)不為0,在判斷擁有鎖的是不是自己呐矾,是則+1苔埋,返回成功,不是則直接返回?fù)屨际 ?br> (5)acquire方法實(shí)際上在AbstractQueuedSynchronizer(AQS)里蜒犯,這個(gè)會(huì)調(diào)用(4)的tryAcquire方法组橄,如果失敗把自己加入到等待隊(duì)列中,成功則直接返回成功罚随。
    (6)tryRelease就是tryAcquire的反向玉工,為鎖狀態(tài)減去準(zhǔn)備release的個(gè)數(shù),也就是釋放鎖的個(gè)數(shù)淘菩。但是這個(gè)要判斷解鎖的是否為當(dāng)前擁有鎖的線程遵班,否則直接失敗。

  2. 多線程有什么要注意的問(wèn)題潮改?
    (1)需要?jiǎng)?chuàng)建大量多線程的程序狭郑,建議使用線程池,避免占用大量資源
    (2)控制并發(fā)數(shù)量汇在,過(guò)大可能導(dǎo)致服務(wù)器無(wú)法支撐翰萨,cpu就那么多,大量并發(fā)執(zhí)行反而卡死了
    (3)通過(guò)一些鎖來(lái)控制并發(fā)導(dǎo)致的共享問(wèn)題
    (4)使用鎖的過(guò)程中注意開(kāi)發(fā)時(shí)候盡量別設(shè)計(jì)成循環(huán)等待的糕殉,容易死鎖
    (5)另外ReentrantLock一類的鎖亩鬼,lock后殖告,一定要記得unlock,否則就死鎖了
    (6)有些線程任務(wù)執(zhí)行完成一部分后雳锋,需要等待其他線程執(zhí)行完成后再執(zhí)行黄绩,這個(gè)時(shí)候可以通過(guò)sleep或者其他方式使其進(jìn)入阻塞狀態(tài)。
    (7)有沒(méi)有優(yōu)先級(jí)玷过?

感謝各位的閱讀爽丹,幫忙點(diǎn)贊,感謝各位冶匹。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末习劫,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子嚼隘,更是在濱河造成了極大的恐慌,老刑警劉巖袒餐,帶你破解...
    沈念sama閱讀 219,110評(píng)論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件飞蛹,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡灸眼,警方通過(guò)查閱死者的電腦和手機(jī)卧檐,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,443評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)焰宣,“玉大人霉囚,你說(shuō)我怎么就攤上這事∝盎” “怎么了盈罐?”我有些...
    開(kāi)封第一講書人閱讀 165,474評(píng)論 0 356
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)闪唆。 經(jīng)常有香客問(wèn)我盅粪,道長(zhǎng),這世上最難降的妖魔是什么悄蕾? 我笑而不...
    開(kāi)封第一講書人閱讀 58,881評(píng)論 1 295
  • 正文 為了忘掉前任票顾,我火速辦了婚禮,結(jié)果婚禮上帆调,老公的妹妹穿的比我還像新娘奠骄。我一直安慰自己,他們只是感情好番刊,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,902評(píng)論 6 392
  • 文/花漫 我一把揭開(kāi)白布含鳞。 她就那樣靜靜地躺著,像睡著了一般撵枢。 火紅的嫁衣襯著肌膚如雪民晒。 梳的紋絲不亂的頭發(fā)上精居,一...
    開(kāi)封第一講書人閱讀 51,698評(píng)論 1 305
  • 那天,我揣著相機(jī)與錄音潜必,去河邊找鬼靴姿。 笑死,一個(gè)胖子當(dāng)著我的面吹牛磁滚,可吹牛的內(nèi)容都是我干的佛吓。 我是一名探鬼主播,決...
    沈念sama閱讀 40,418評(píng)論 3 419
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼垂攘,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼维雇!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起晒他,我...
    開(kāi)封第一講書人閱讀 39,332評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤吱型,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后陨仅,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體津滞,經(jīng)...
    沈念sama閱讀 45,796評(píng)論 1 316
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,968評(píng)論 3 337
  • 正文 我和宋清朗相戀三年灼伤,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了触徐。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 40,110評(píng)論 1 351
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡狐赡,死狀恐怖撞鹉,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情颖侄,我是刑警寧澤鸟雏,帶...
    沈念sama閱讀 35,792評(píng)論 5 346
  • 正文 年R本政府宣布,位于F島的核電站发皿,受9級(jí)特大地震影響崔慧,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜穴墅,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,455評(píng)論 3 331
  • 文/蒙蒙 一惶室、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧玄货,春花似錦皇钞、人聲如沸。這莊子的主人今日做“春日...
    開(kāi)封第一講書人閱讀 32,003評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至隘世,卻和暖如春可柿,著一層夾襖步出監(jiān)牢的瞬間鸠踪,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書人閱讀 33,130評(píng)論 1 272
  • 我被黑心中介騙來(lái)泰國(guó)打工复斥, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留营密,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 48,348評(píng)論 3 373
  • 正文 我出身青樓目锭,卻偏偏與公主長(zhǎng)得像评汰,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子痢虹,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,047評(píng)論 2 355

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