java實(shí)現(xiàn)線程有哪幾種方式
1.繼承Thread類實(shí)現(xiàn)多線程
2.實(shí)現(xiàn)Runnable接口方式實(shí)現(xiàn)多線程
3.使用線程池:如ExecutorService,Callable仪缸,F(xiàn)uture
第一種和第二種方式相比:java類只能允許繼承一個(gè)父類贵涵,可以實(shí)現(xiàn)多個(gè)接口;其次恰画,在第一種方式中用this可以獲取當(dāng)前線程宾茂,第二種方式獲取當(dāng)前線程只能通過Thread.currentThread()
第三種:線程的創(chuàng)建和釋放,需要占用不小的內(nèi)存和資源拴还。如果每次需要使用線程時(shí)跨晴,都new 一個(gè)Thread的話,難免會(huì)造成資源的浪費(fèi)片林,而且可以無限制創(chuàng)建端盆,之間相互競(jìng)爭(zhēng),會(huì)導(dǎo)致過多占用系統(tǒng)資源導(dǎo)致系統(tǒng)癱瘓费封, ExecutorService是Java提供的線程池
public ThreadPoolExecutor(int corePoolSize,
int maximumPoolSize,
long keepAliveTime,
TimeUnit unit,
BlockingQueue<Runnable> workQueue,
ThreadFactory threadFactory,
corePoolSize:核心線程數(shù)
maximumPoolSize:最大線程數(shù)
poolSize:線程池中當(dāng)前線程的數(shù)量
那么poolSize焕妙、corePoolSize、maximumPoolSize三者的關(guān)系是如何的呢弓摘?
當(dāng)新提交一個(gè)任務(wù)時(shí):
(1)如果poolSize<corePoolSize焚鹊,新增加一個(gè)線程處理新的任務(wù)。
(2)如果poolSize=corePoolSize韧献,新任務(wù)會(huì)被放入阻塞隊(duì)列等待末患。
(3)如果阻塞隊(duì)列的容量達(dá)到上限,且這時(shí)poolSize<maximumPoolSize锤窑,新增線程來處理任務(wù)璧针。
(4)如果阻塞隊(duì)列滿了,且poolSize=maximumPoolSize果复,那么線程池已經(jīng)達(dá)到極限陈莽,會(huì)根據(jù)飽和策略RejectedExecutionHandler拒絕新的任務(wù)
ExecutorService分為以下幾種線程池:可緩存線程池newCachedThreadPool(),其中創(chuàng)建的都是非核心線程,走搁;單線程newSingleThreadExecutor()独柑;
固定線程池newFixedThreadPool(3);定時(shí)線程池
線程同步有哪幾種方法
Synchronized,Lock鎖,分布式鎖
Synchronized,Lock鎖的區(qū)別:
1.Synchronized是java內(nèi)置關(guān)鍵字私植,Lock是java 類 Lock lock = new ReentrantLock()
2.synchronized無法判斷是否獲取鎖的狀態(tài)忌栅,Lock可以判斷是否獲取鎖lock.tryLock()
3.synchronized的鎖可重入、不可中斷曲稼、非公平索绪,而Lock鎖可重入、可判斷贫悄、可公平
4.Lock鎖適合大量同步的代碼的同步問題瑞驱,synchronized鎖適合代碼少量的同步問題
5.synchronized會(huì)自動(dòng)釋放鎖(a 線程執(zhí)行完同步代碼會(huì)釋放鎖 ;b 線程執(zhí)行過程中發(fā)生異常會(huì)釋放鎖)窄坦,Lock需在finally中手工釋放鎖(unlock()方法釋放鎖)唤反,否則容易造成線程死鎖;
6.用synchronized關(guān)鍵字的兩個(gè)線程1和線程2鸭津,如果當(dāng)前線程1獲得鎖彤侍,線程2線程等待。如果線程1阻塞逆趋,線程2則會(huì)一直等待下去盏阶,而Lock鎖就不一定會(huì)等待下去,如果嘗試獲取不到鎖闻书,線程可以不用一直等待就結(jié)束了//lock.tryLock(3000, TimeUnit.MILLISECONDS) //嘗試獲取鎖 獲取不到鎖名斟,就等3秒,如果3秒后還是獲取不到就返回false
synchronized與volatile區(qū)別
同步塊(或方法)和 volatile 變量惠窄。這兩種機(jī)制的提出都是為了實(shí)現(xiàn)代碼線程的安全性蒸眠。其中 Volatile 變量的同步性較差(但有時(shí)它更簡(jiǎn)單并且開銷更低),而且其使用也更容易出錯(cuò)杆融。volatile關(guān)鍵字用于聲明簡(jiǎn)單類型變量,如int霜运、float脾歇、boolean等數(shù)據(jù)類型。如果這些簡(jiǎn)單數(shù)據(jù)類型聲明為volatile淘捡,對(duì)它們的操作就會(huì)變成原子級(jí)別的藕各。但這有一定的限制。并不是只要簡(jiǎn)單類型變量使用volatile修飾焦除,對(duì)這個(gè)變量的所有操作都是原來操作激况,當(dāng)變量的值由自身的上一個(gè)決定時(shí),如n=n+1、n++等乌逐,volatile關(guān)鍵字將失效竭讳,只有當(dāng)變量的值和自身上一個(gè)值無關(guān)時(shí)對(duì)該變量的操作才是原子級(jí)別的,如n = m + 1浙踢,這個(gè)就是原級(jí)別的绢慢。所以在使用volatile關(guān)鍵時(shí)一定要謹(jǐn)慎,如果自己沒有把握洛波,可以使用synchronized來代替volatile胰舆。
java中notify和notifyAll的區(qū)別
notify方法不能喚醒某個(gè)具體的線程,而notifyAll喚醒所有的線程并允許他們爭(zhēng)奪鎖蹬挤,確保至少有一個(gè)線程能繼續(xù)運(yùn)行
為什么wait/notify/notifyAll這些方法不在thread類里面
一個(gè)明顯的原因就是java提供的鎖是對(duì)象級(jí)而不是線程級(jí)缚窿。每個(gè)對(duì)象都有鎖,通過線程獲得焰扳。如果線程需要等待某些鎖那么調(diào)用對(duì)象中wait方法才有意義
什么是死鎖
死鎖是兩個(gè)線程相互等待對(duì)方釋放對(duì)象鎖
啟動(dòng)線程方法start()和run()有什么區(qū)別
只有調(diào)用了start方法倦零,才會(huì)表現(xiàn)多線程的特性,不同線程的run方法里面的帶脈交替執(zhí)行蓝翰。如果只是調(diào)用了run方法光绕,那么代碼還是同步執(zhí)行,必須等待一個(gè)線程的run方法里面的代碼全部執(zhí)行完畜份,才會(huì)執(zhí)行其自己的run方法里面的代碼
多線程通信
wait/notify
java中用到了什么線程調(diào)度算法
搶占式诞帐。一個(gè)線程的cpu用完后,操作系統(tǒng)會(huì)根據(jù)線程優(yōu)先級(jí)爆雹,線程饑餓情況等情況分配某個(gè)線程
synchronized有哪幾種用法
鎖類停蕉,鎖方法,鎖代碼塊
活鎖钙态,饑餓慧起,無鎖,死鎖
死鎖:多個(gè)線程互相占用對(duì)方資源的鎖册倒,又相互等待對(duì)方釋放鎖蚓挤,若無外力干涉,這些線程則一直處于阻塞你的假死狀態(tài)驻子,形成死鎖
活鎖:指拿到資源卻又相互釋放不執(zhí)行灿意,這個(gè)資源在多個(gè)線程之間跳動(dòng)又得不到執(zhí)行
饑餓:指優(yōu)先級(jí)高的線程一直占著優(yōu)先級(jí)低的資源,導(dǎo)致優(yōu)先級(jí)低的線程無法得到執(zhí)行崇呵,處于長(zhǎng)久等待中