【72期】面試官:對(duì)并發(fā)熟悉嗎?說(shuō)一下synchronized與Lock的區(qū)別與使用
閱讀本文大概需要 8 分鐘。
來(lái)自:https://blog.csdn.net/u012403290/
引言:
技術(shù)點(diǎn):
1、線程與進(jìn)程:
2、Thread的幾個(gè)重要方法:
start()方法,調(diào)用該方法開始執(zhí)行該線程;
stop()方法,調(diào)用該方法強(qiáng)制結(jié)束該線程執(zhí)行;
join方法,調(diào)用該方法等待該線程結(jié)束。
sleep()方法,調(diào)用該方法該線程進(jìn)入等待。
run()方法,調(diào)用該方法直接執(zhí)行線程的run()方法,但是線程調(diào)用start()方法時(shí)也會(huì)運(yùn)行run()方法,區(qū)別就是一個(gè)是由線程調(diào)度運(yùn)行run()方法,一個(gè)是直接調(diào)用了線程中的run()方法!!
3、線程狀態(tài):

新建狀態(tài):新建線程對(duì)象,并沒有調(diào)用start()方法之前
就緒狀態(tài):調(diào)用start()方法之后線程就進(jìn)入就緒狀態(tài),但是并不是說(shuō)只要調(diào)用start()方法線程就馬上變?yōu)楫?dāng)前線程,在變?yōu)楫?dāng)前線程之前都是為就緒狀態(tài)。值得一提的是,線程在睡眠和掛起中恢復(fù)的時(shí)候也會(huì)進(jìn)入就緒狀態(tài)哦。
運(yùn)行狀態(tài):線程被設(shè)置為當(dāng)前線程,開始執(zhí)行run()方法。就是線程進(jìn)入運(yùn)行狀態(tài)
阻塞狀態(tài):線程被暫停,比如說(shuō)調(diào)用sleep()方法后線程就進(jìn)入阻塞狀態(tài)
死亡狀態(tài):線程執(zhí)行結(jié)束
4、鎖類型
可重入鎖:在執(zhí)行對(duì)象中所有同步方法不用再次獲得鎖
可中斷鎖:在等待獲取鎖過程中可中斷
公平鎖:按等待獲取鎖的線程的等待時(shí)間進(jìn)行獲取,等待時(shí)間長(zhǎng)的具有優(yōu)先獲取鎖權(quán)利
讀寫鎖:對(duì)資源讀取和寫入的時(shí)候拆分為2部分處理,讀的時(shí)候可以多線程一起讀,寫的時(shí)候必須同步地寫
synchronized與Lock的區(qū)別

Lock詳細(xì)介紹與Demo
public?interface?Lock?{
????/**
?????*?Acquires?the?lock.
?????*/
????void?lock();
????/**
?????*?Acquires?the?lock?unless?the?current?thread?is
?????*?{@linkplain?Thread#interrupt?interrupted}.
?????*/
????void?lockInterruptibly()?throws?InterruptedException;
????/**
?????*?Acquires?the?lock?only?if?it?is?free?at?the?time?of?invocation.
?????*/
????boolean?tryLock();
????/**
?????*?Acquires?the?lock?if?it?is?free?within?the?given?waiting?time?and?the
?????*?current?thread?has?not?been?{@linkplain?Thread#interrupt?interrupted}.
?????*/
????boolean?tryLock(long?time,?TimeUnit?unit)?throws?InterruptedException;
????/**
?????*?Releases?the?lock.
?????*/
????void?unlock();
}
lock():獲取鎖,如果鎖被暫用則一直等待
unlock():釋放鎖
tryLock(): 注意返回類型是boolean,如果獲取鎖的時(shí)候鎖被占用就返回false,否則返回true
tryLock(long time, TimeUnit unit):比起tryLock()就是給了一個(gè)時(shí)間期限,保證等待參數(shù)時(shí)間
lockInterruptibly():用該鎖的獲得方式,如果線程在獲取鎖的階段進(jìn)入了等待,那么可以中斷此線程,先去做別的事
lock():
package?com.brickworkers;
import?java.util.concurrent.locks.Lock;
import?java.util.concurrent.locks.ReentrantLock;
public?class?LockTest?{
????private?Lock?lock?=?new?ReentrantLock();
????//需要參與同步的方法
????private?void?method(Thread?thread){
????????lock.lock();
????????try?{
????????????System.out.println("線程名"+thread.getName()?+?"獲得了鎖");
????????}catch(Exception?e){
????????????e.printStackTrace();
????????}?finally?{
????????????System.out.println("線程名"+thread.getName()?+?"釋放了鎖");
????????????lock.unlock();
????????}
????}
????public?static?void?main(String[]?args)?{
????????LockTest?lockTest?=?new?LockTest();
????????//線程1
????????Thread?t1?=?new?Thread(new?Runnable()?{
????????????@Override
????????????public?void?run()?{
????????????????lockTest.method(Thread.currentThread());
????????????}
????????},?"t1");
????????Thread?t2?=?new?Thread(new?Runnable()?{
????????????@Override
????????????public?void?run()?{
????????????????lockTest.method(Thread.currentThread());
????????????}
????????},?"t2");
????????t1.start();
????????t2.start();
????}
}
//執(zhí)行情況:線程名t1獲得了鎖
//?????????線程名t1釋放了鎖
//?????????線程名t2獲得了鎖
//?????????線程名t2釋放了鎖
tryLock():
package?com.brickworkers;
import?java.util.concurrent.locks.Lock;
import?java.util.concurrent.locks.ReentrantLock;
public?class?LockTest?{
????private?Lock?lock?=?new?ReentrantLock();
????//需要參與同步的方法
????private?void?method(Thread?thread){
/*????????lock.lock();
????????try?{
????????????System.out.println("線程名"+thread.getName()?+?"獲得了鎖");
????????}catch(Exception?e){
????????????e.printStackTrace();
????????}?finally?{
????????????System.out.println("線程名"+thread.getName()?+?"釋放了鎖");
????????????lock.unlock();
????????}*/
????????if(lock.tryLock()){
????????????try?{
????????????????System.out.println("線程名"+thread.getName()?+?"獲得了鎖");
????????????}catch(Exception?e){
????????????????e.printStackTrace();
????????????}?finally?{
????????????????System.out.println("線程名"+thread.getName()?+?"釋放了鎖");
????????????????lock.unlock();
????????????}
????????}else{
????????????System.out.println("我是"+Thread.currentThread().getName()+"有人占著鎖,我就不要啦");
????????}
????}
????public?static?void?main(String[]?args)?{
????????LockTest?lockTest?=?new?LockTest();
????????//線程1
????????Thread?t1?=?new?Thread(new?Runnable()?{
????????????@Override
????????????public?void?run()?{
????????????????lockTest.method(Thread.currentThread());
????????????}
????????},?"t1");
????????Thread?t2?=?new?Thread(new?Runnable()?{
????????????@Override
????????????public?void?run()?{
????????????????lockTest.method(Thread.currentThread());
????????????}
????????},?"t2");
????????t1.start();
????????t2.start();
????}
}
//執(zhí)行結(jié)果:?線程名t2獲得了鎖
//?????????我是t1有人占著鎖,我就不要啦
//?????????線程名t2釋放了鎖
?/**
?????*?Sync?object?for?non-fair?locks
?????*/
????static?final?class?NonfairSync?extends?Sync?{
????????private?static?final?long?serialVersionUID?=?7316153563782823691L;
????????/**
?????????*?Performs?lock.??Try?immediate?barge,?backing?up?to?normal
?????????*?acquire?on?failure.
?????????*/
????????final?void?lock()?{
????????????if?(compareAndSetState(0,?1))
????????????????setExclusiveOwnerThread(Thread.currentThread());
????????????else
????????????????acquire(1);
????????}
????????protected?final?boolean?tryAcquire(int?acquires)?{
????????????return?nonfairTryAcquire(acquires);
????????}
????}
????/**
?????*?Sync?object?for?fair?locks
?????*/
????static?final?class?FairSync?extends?Sync?{
????????private?static?final?long?serialVersionUID?=?-3000897897090466540L;
????????final?void?lock()?{
????????????acquire(1);
????????}
????????/**
?????????*?Fair?version?of?tryAcquire.??Don't?grant?access?unless
?????????*?recursive?call?or?no?waiters?or?is?first.
?????????*/
????????protected?final?boolean?tryAcquire(int?acquires)?{
????????????final?Thread?current?=?Thread.currentThread();
????????????int?c?=?getState();
????????????if?(c?==?0)?{
????????????????if?(!hasQueuedPredecessors()?&&
????????????????????compareAndSetState(0,?acquires))?{
????????????????????setExclusiveOwnerThread(current);
????????????????????return?true;
????????????????}
????????????}
????????????else?if?(current?==?getExclusiveOwnerThread())?{
????????????????int?nextc?=?c?+?acquires;
????????????????if?(nextc?0)
????????????????????throw?new?Error("Maximum?lock?count?exceeded");
????????????????setState(nextc);
????????????????return?true;
????????????}
????????????return?false;
????????}
????}
???public?ReentrantLock()?{
????????sync?=?new?NonfairSync();//默認(rèn)非公平鎖
????}
尾記錄:
補(bǔ)充
1、兩種鎖的底層實(shí)現(xiàn)方式:


那如何教育呢?
1、線程自旋和適應(yīng)性自旋
2、鎖消除
String?str1="qwe";
String?str2="asd";
String?str3=str1+str2;
StringBuffer?sb?=?new?StringBuffer();
sb.append("qwe");
sb.append("asd");
3、鎖粗化
4、輕量級(jí)鎖
5、偏向鎖
推薦閱讀:
【71期】面試官:對(duì)并發(fā)熟悉嗎?談?wù)勀銓?duì)Java中常用的幾種線程池的理解
【70期】面試官:對(duì)并發(fā)熟悉嗎?談?wù)剬?duì)volatile的使用及其原理
【69期】面試官:對(duì)并發(fā)熟悉嗎?談?wù)劸€程間的協(xié)作(wait/notify/sleep/yield/join)
微信掃描二維碼,關(guān)注我的公眾號(hào)
朕已閱?

