一区二区三区在线-一区二区三区亚洲视频-一区二区三区亚洲-一区二区三区午夜-一区二区三区四区在线视频-一区二区三区四区在线免费观看

服務(wù)器之家:專注于服務(wù)器技術(shù)及軟件下載分享
分類導(dǎo)航

PHP教程|ASP.NET教程|Java教程|ASP教程|編程技術(shù)|正則表達(dá)式|C/C++|IOS|C#|Swift|Android|VB|R語言|JavaScript|易語言|vb.net|

服務(wù)器之家 - 編程語言 - Java教程 - Java多線程基礎(chǔ)——Lock類

Java多線程基礎(chǔ)——Lock類

2020-08-02 11:54byhieg Java教程

Lock類是Java類來提供的功能,豐富的api使得Lock類的同步功能比synchronized的同步更強(qiáng)大。本文對(duì)此進(jìn)行詳細(xì)介紹,下面跟著小編一起來看下吧

之前已經(jīng)說道,JVM提供了synchronized關(guān)鍵字來實(shí)現(xiàn)對(duì)變量的同步訪問以及用wait和notify來實(shí)現(xiàn)線程間通信。在jdk1.5以后,JAVA提供了Lock類來實(shí)現(xiàn)和synchronized一樣的功能,并且還提供了Condition來顯示線程間通信。

Lock類是Java類來提供的功能,豐富的api使得Lock類的同步功能比synchronized的同步更強(qiáng)大。本文章的所有代碼均在Lock類例子的代碼

本文主要介紹一下內(nèi)容:

  1. Lock類
  2. Lock類其他功能
  3. Condition類
  4. Condition類其他功能
  5. 讀寫鎖

Lock類

Lock類實(shí)際上是一個(gè)接口,我們?cè)趯?shí)例化的時(shí)候?qū)嶋H上是實(shí)例化實(shí)現(xiàn)了該接口的類Lock lock = new ReentrantLock();。用synchronized的時(shí)候,synchronized可以修飾方法,或者對(duì)一段代碼塊進(jìn)行同步處理。

前面講過,針對(duì)需要同步處理的代碼設(shè)置對(duì)象監(jiān)視器,比整個(gè)方法用synchronized修飾要好。Lock類的用法也是這樣,通過Lock對(duì)象lock,用lock.lock來加鎖,用lock.unlock來釋放鎖。在兩者中間放置需要同步處理的代碼。

具體的例子如下:

?
1
2
3
4
5
6
7
8
9
10
public class MyConditionService {
 private Lock lock = new ReentrantLock();
 public void testMethod(){
  lock.lock();
  for (int i = 0 ;i < 5;i++){
   System.out.println("ThreadName = " + Thread.currentThread().getName() + (" " + (i + 1)));
  }
  lock.unlock();
 }
}

測試的代碼如下:

?
1
2
3
4
5
6
7
8
MyConditionService service = new MyConditionService();
new Thread(service::testMethod).start();
new Thread(service::testMethod).start();
new Thread(service::testMethod).start();
new Thread(service::testMethod).start();
new Thread(service::testMethod).start();
 
Thread.sleep(1000 * 5);

結(jié)果太長就不放出來,具體可以看我源碼。總之,就是每個(gè)線程的打印1-5都是同步進(jìn)行,順序沒有亂。

通過下面的例子,可以看出Lock對(duì)象加鎖的時(shí)候也是一個(gè)對(duì)象鎖,持續(xù)對(duì)象監(jiān)視器的線程才能執(zhí)行同步代碼,其他線程只能等待該線程釋放對(duì)象監(jiān)視器。

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
public class MyConditionMoreService {
 private Lock lock = new ReentrantLock();
 public void methodA(){
  try{
   lock.lock();
   System.out.println("methodA begin ThreadName=" + Thread.currentThread().getName() +
     " time=" + System.currentTimeMillis());
   Thread.sleep(1000 * 5);
   System.out.println("methodA end ThreadName=" + Thread.currentThread().getName() +
     " time=" + System.currentTimeMillis());
  }catch (Exception e){
   e.printStackTrace();
  }finally {
   lock.unlock();
  }
 }
 public void methodB(){
  try{
   lock.lock();
   System.out.println("methodB begin ThreadName=" + Thread.currentThread().getName() +
     " time=" + System.currentTimeMillis());
   Thread.sleep(1000 * 5);
   System.out.println("methodB end ThreadName=" + Thread.currentThread().getName() +
     " time=" + System.currentTimeMillis());
  }catch (Exception e){
   e.printStackTrace();
  }finally {
   lock.unlock();
  }
 }
}

測試代碼如下:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
public void testMethod() throws Exception {
  MyConditionMoreService service = new MyConditionMoreService();
  ThreadA a = new ThreadA(service);
  a.setName("A");
  a.start();
  ThreadA aa = new ThreadA(service);
  aa.setName("AA");
  aa.start();
  ThreadB b = new ThreadB(service);
  b.setName("B");
  b.start();
  ThreadB bb = new ThreadB(service);
  bb.setName("BB");
  bb.start();
  Thread.sleep(1000 * 30);
 }
public class ThreadA extends Thread{
 private MyConditionMoreService service;
 public ThreadA(MyConditionMoreService service){
  this.service = service;
 }
 @Override
 public void run() {
  service.methodA();
 }
}
public class ThreadB extends Thread{
 private MyConditionMoreService service;
 public ThreadB(MyConditionMoreService service){
  this.service = service;
 }
 @Override
 public void run() {
  super.run();
  service.methodB();
 }
}

結(jié)果如下:

?
1
2
3
4
5
6
7
8
methodA begin ThreadName=A time=1485590913520
methodA end ThreadName=A time=1485590918522
methodA begin ThreadName=AA time=1485590918522
methodA end ThreadName=AA time=1485590923525
methodB begin ThreadName=B time=1485590923525
methodB end ThreadName=B time=1485590928528
methodB begin ThreadName=BB time=1485590928529
methodB end ThreadName=BB time=1485590933533

可以看出Lock類加鎖確實(shí)是對(duì)象鎖。針對(duì)同一個(gè)lock對(duì)象執(zhí)行的lock.lock是獲得對(duì)象監(jiān)視器的線程才能執(zhí)行同步代碼 其他線程都要等待。

在這個(gè)例子中,加鎖,和釋放鎖都是在try-finally。這樣的好處是在任何異常發(fā)生的情況下,都能保障鎖的釋放。

Lock類其他的功能

如果Lock類只有l(wèi)ock和unlock方法也太簡單了,Lock類提供了豐富的加鎖的方法和對(duì)加鎖的情況判斷。主要有

  • 實(shí)現(xiàn)鎖的公平
  • 獲取當(dāng)前線程調(diào)用lock的次數(shù),也就是獲取當(dāng)前線程鎖定的個(gè)數(shù)
  • 獲取等待鎖的線程數(shù)
  • 查詢指定的線程是否等待獲取此鎖定
  • 查詢是否有線程等待獲取此鎖定
  • 查詢當(dāng)前線程是否持有鎖定
  • 判斷一個(gè)鎖是不是被線程持有
  • 加鎖時(shí)如果中斷則不加鎖,進(jìn)入異常處理
  • 嘗試加鎖,如果該鎖未被其他線程持有的情況下成功

實(shí)現(xiàn)公平鎖

在實(shí)例化鎖對(duì)象的時(shí)候,構(gòu)造方法有2個(gè),一個(gè)是無參構(gòu)造方法,一個(gè)是傳入一個(gè)boolean變量的構(gòu)造方法。當(dāng)傳入值為true的時(shí)候,該鎖為公平鎖。默認(rèn)不傳參數(shù)是非公平鎖。

公平鎖:按照線程加鎖的順序來獲取鎖

非公平鎖:隨機(jī)競爭來得到鎖

此外,JAVA還提供isFair()來判斷一個(gè)鎖是不是公平鎖。

獲取當(dāng)前線程鎖定的個(gè)數(shù)

Java提供了getHoldCount()方法來獲取當(dāng)前線程的鎖定個(gè)數(shù)。所謂鎖定個(gè)數(shù)就是當(dāng)前線程調(diào)用lock方法的次數(shù)。一般一個(gè)方法只會(huì)調(diào)用一個(gè)lock方法,但是有可能在同步代碼中還有調(diào)用了別的方法,那個(gè)方法內(nèi)部有同步代碼。這樣,getHoldCount()返回值就是大于1。

下面的方法用來判斷等待鎖的情況

獲取等待鎖的線程數(shù)

Java提供了getQueueLength()方法來得到等待鎖釋放的線程的個(gè)數(shù)。

查詢指定的線程是否等待獲取此鎖定

Java提供了hasQueuedThread(Thread thread)查詢?cè)揟hread是否等待該lock對(duì)象的釋放。

查詢是否有線程等待獲取此鎖定

同樣,Java提供了一個(gè)簡單判斷是否有線程在等待鎖釋放即hasQueuedThreads()。

下面的方法用來判斷持有鎖的情況

查詢當(dāng)前線程是否持有鎖定

Java不僅提供了判斷是否有線程在等待鎖釋放的方法,還提供了是否當(dāng)前線程持有鎖即isHeldByCurrentThread(),判斷當(dāng)前線程是否有此鎖定。

判斷一個(gè)鎖是不是被線程持有

同樣,Java提供了簡單判斷一個(gè)鎖是不是被一個(gè)線程持有,即isLocked()

下面的方法用來實(shí)現(xiàn)多種方式加鎖

加鎖時(shí)如果中斷則不加鎖,進(jìn)入異常處理

Lock類提供了多種選擇的加鎖方法,lockInterruptibly()也可以實(shí)現(xiàn)加鎖,但是當(dāng)線程被中斷的時(shí)候,就會(huì)加鎖失敗,進(jìn)行異常處理階段。一般這種情況出現(xiàn)在該線程已經(jīng)被打上interrupted的標(biāo)記了。

嘗試加鎖,如果該鎖未被其他線程持有的情況下成功

Java提供了tryLock()方法來進(jìn)行嘗試加鎖,只有該鎖未被其他線程持有的基礎(chǔ)上,才會(huì)成功加鎖。

上面介紹了Lock類來實(shí)現(xiàn)代碼的同步處理,下面介紹Condition類來實(shí)現(xiàn)wait/notify機(jī)制。

Condition類

Condition是Java提供了來實(shí)現(xiàn)等待/通知的類,Condition類還提供比wait/notify更豐富的功能,Condition對(duì)象是由lock對(duì)象所創(chuàng)建的。但是同一個(gè)鎖可以創(chuàng)建多個(gè)Condition的對(duì)象,即創(chuàng)建多個(gè)對(duì)象監(jiān)視器。這樣的好處就是可以指定喚醒線程。notify喚醒的線程是隨機(jī)喚醒一個(gè)。

下面,看一個(gè)例子,顯示簡單的等待/通知

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
public class ConditionWaitNotifyService {
 private Lock lock = new ReentrantLock();
 public Condition condition = lock.newCondition();
 public void await(){
  try{
   lock.lock();
   System.out.println("await的時(shí)間為 " + System.currentTimeMillis());
   condition.await();
   System.out.println("await結(jié)束的時(shí)間" + System.currentTimeMillis());
  }catch (Exception e){
   e.printStackTrace();
  }finally {
   lock.unlock();
  }
 }
 public void signal(){
  try{
   lock.lock();
   System.out.println("sign的時(shí)間為" + System.currentTimeMillis());
   condition.signal();
  }finally {
   lock.unlock();
  }
 }
}

測試的代碼如下:

?
1
2
3
4
5
ConditionWaitNotifyService service = new ConditionWaitNotifyService();
new Thread(service::await).start();
Thread.sleep(1000 * 3);
service.signal();
Thread.sleep(1000);

結(jié)果如下:

?
1
2
3
await的時(shí)間為 1485610107421
sign的時(shí)間為1485610110423
await結(jié)束的時(shí)間1485610110423

condition對(duì)象通過lock.newCondition()來創(chuàng)建,用condition.await()來實(shí)現(xiàn)讓線程等待,是線程進(jìn)入阻塞。用condition.signal()來實(shí)現(xiàn)喚醒線程。喚醒的線程是用同一個(gè)conditon對(duì)象調(diào)用await()方法而進(jìn)入阻塞。并且和wait/notify一樣,await()和signal()也是在同步代碼區(qū)內(nèi)執(zhí)行。

此外看出await結(jié)束的語句是在獲取通知之后才執(zhí)行,確實(shí)實(shí)現(xiàn)了wait/notify的功能。下面這個(gè)例子是展示喚醒制定的線程。

?
1
2
3
4
5
6
7
8
9
10
ConditionAllService service = new ConditionAllService();
Thread a = new Thread(service::awaitA);
a.setName("A");
a.start();
Thread b = new Thread(service::awaitB);
b.setName("B");
b.start();
Thread.sleep(1000 * 3);
service.signAAll();
Thread.sleep(1000 * 4);

結(jié)果如下:

?
1
2
3
4
begin awaitA時(shí)間為 1485611065974ThreadName=A
begin awaitB時(shí)間為 1485611065975ThreadName=B
signAll的時(shí)間為1485611068979ThreadName=main
end awaitA時(shí)間為1485611068979ThreadName=A

該結(jié)果確實(shí)展示用同一個(gè)condition對(duì)象來實(shí)現(xiàn)等待通知。

對(duì)于等待/通知機(jī)制,簡化而言,就是等待一個(gè)條件,當(dāng)條件不滿足時(shí),就進(jìn)入等待,等條件滿足時(shí),就通知等待的線程開始執(zhí)行。為了實(shí)現(xiàn)這種功能,需要進(jìn)行wait的代碼部分與需要進(jìn)行通知的代碼部分必須放在同一個(gè)對(duì)象監(jiān)視器里面。執(zhí)行才能實(shí)現(xiàn)多個(gè)阻塞的線程同步執(zhí)行代碼,等待與通知的線程也是同步進(jìn)行。對(duì)于wait/notify而言,對(duì)象監(jiān)視器與等待條件結(jié)合在一起 即synchronized(對(duì)象)利用該對(duì)象去調(diào)用wait以及notify。但是對(duì)于Condition類,是對(duì)象監(jiān)視器與條件分開,Lock類來實(shí)現(xiàn)對(duì)象監(jiān)視器,condition對(duì)象來負(fù)責(zé)條件,去調(diào)用await以及signal。

Condition類的其他功能

和wait類提供了一個(gè)最長等待時(shí)間,awaitUntil(Date deadline)在到達(dá)指定時(shí)間之后,線程會(huì)自動(dòng)喚醒。但是無論是await或者awaitUntil,當(dāng)線程中斷時(shí),進(jìn)行阻塞的線程會(huì)產(chǎn)生中斷異常。Java提供了一個(gè)awaitUninterruptibly的方法,使即使線程中斷時(shí),進(jìn)行阻塞的線程也不會(huì)產(chǎn)生中斷異常。

讀寫鎖

Lock類除了提供了ReentrantLock的鎖以外,還提供了ReentrantReadWriteLock的鎖。讀寫鎖分成兩個(gè)鎖,一個(gè)鎖是讀鎖,一個(gè)鎖是寫鎖。讀鎖與讀鎖之間是共享的,讀鎖與寫鎖之間是互斥的,寫鎖與寫鎖之間也是互斥的。

看下面的讀讀共享的例子:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
public class ReadReadService {
 private ReentrantReadWriteLock lock = new ReentrantReadWriteLock();
 public void read(){
  try{
   try{
    lock.readLock().lock();
    System.out.println("獲得讀鎖" + Thread.currentThread().getName() +
    " " + System.currentTimeMillis());
    Thread.sleep(1000 * 10);
   }finally {
    lock.readLock().unlock();
   }
  }catch (InterruptedException e){
   e.printStackTrace();
  }
 }
}

測試的代碼和結(jié)果如下:

?
1
2
3
4
5
6
7
ReadReadService service = new ReadReadService();
Thread a = new Thread(service::read);
a.setName("A");
Thread b = new Thread(service::read);
b.setName("B");
a.start();
b.start();

結(jié)果如下:

?
1
2
獲得讀鎖A 1485614976979
獲得讀鎖B 1485614976981

兩個(gè)線程幾乎同時(shí)執(zhí)行同步代碼。

下面的例子是寫寫互斥的例子

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
public class WriteWriteService {
 private ReentrantReadWriteLock lock = new ReentrantReadWriteLock();
 public void write(){
  try{
   try{
    lock.writeLock().lock();
    System.out.println("獲得寫鎖" + Thread.currentThread().getName() +
      " " +System.currentTimeMillis());
    Thread.sleep(1000 * 10);
   }finally {
    lock.writeLock().unlock();
   }
  }catch (InterruptedException e){
   e.printStackTrace();
  }
 }
}

測試代碼和結(jié)果如下:

?
1
2
3
4
5
6
7
8
WriteWriteService service = new WriteWriteService();
Thread a = new Thread(service::write);
a.setName("A");
Thread b = new Thread(service::write);
b.setName("B");
a.start();
b.start();
Thread.sleep(1000 * 30);

結(jié)果如下:

?
1
2
獲得寫鎖A 1485615316519
獲得寫鎖B 1485615326524

兩個(gè)線程同步執(zhí)行代碼

讀寫互斥的例子:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
public class WriteReadService {
 private ReentrantReadWriteLock lock = new ReentrantReadWriteLock();
 public void read(){
  try{
   try{
    lock.readLock().lock();
    System.out.println("獲得讀鎖" + Thread.currentThread().getName()
      + " " + System.currentTimeMillis());
    Thread.sleep(1000 * 10);
   }finally {
    lock.readLock().unlock();
   }
  }catch (InterruptedException e){
   e.printStackTrace();
  }
 }
 public void write(){
  try{
   try{
    lock.writeLock().lock();
    System.out.println("獲得寫鎖" + Thread.currentThread().getName()
      + " " + System.currentTimeMillis());
    Thread.sleep(1000 * 10);
   }finally {
    lock.writeLock().unlock();
   }
  }catch (InterruptedException e){
   e.printStackTrace();
  }
 }
}

測試的代碼如下:

?
1
2
3
4
5
6
7
8
9
WriteReadService service = new WriteReadService();
Thread a = new Thread(service::write);
a.setName("A");
a.start();
Thread.sleep(1000);
Thread b = new Thread(service::read);
b.setName("B");
b.start();
Thread.sleep(1000 * 30);

結(jié)果如下:

?
1
2
獲得寫鎖A 1485615633790
獲得讀鎖B 1485615643792

兩個(gè)線程讀寫之間也是同步執(zhí)行代碼。

總結(jié)

本文介紹了新的同步代碼的方式Lock類以及新的等待/通知機(jī)制的實(shí)現(xiàn)Condition類。本文只是很簡單的介紹了他們的概念和使用的方式。關(guān)于Condition以及讀寫鎖還有更多的內(nèi)容,將放在以后的博客中。

以上就是本文的全部內(nèi)容,希望本文的內(nèi)容對(duì)大家的學(xué)習(xí)或者工作能帶來一定的幫助,同時(shí)也希望多多支持服務(wù)器之家!

原文鏈接:http://www.cnblogs.com/qifengshi/p/6354890.html

延伸 · 閱讀

精彩推薦
主站蜘蛛池模板: 欧美一区不卡二区不卡三区 | 秋霞一级毛片 | 亚洲成人影院在线 | 精品欧美一区二区三区久久久 | 女性全身裸露无遮挡 | 男女真实无遮挡xx00动态图软件 | 亚洲国产欧美久久香综合 | 欧美精品国产一区二区三区 | 古装一级无遮挡毛片免费观看 | 男生的j桶女人屁免费视频 男生操男生 | 欧美整片完整片视频在线 | 日本久久影视 | 亚洲视频精选 | 日本视频观看 | 亚洲黄色天堂 | 国内精品哆啪啪 | 成 人免费va视频 | 精品一区二区三区免费观看 | 亚洲香蕉综合在人在线视看 | 视频污版 | 日本888xxxx| 国产亚洲一欧美一区二区三区 | 91亚洲精品第一综合不卡播放 | 国产小视频在线 | 草莓香蕉绿巨人丝瓜榴莲污在线观看 | 久久中文字幕乱码免费 | 亚洲视频免费在线看 | 男人天堂a| 国产动作大片 | 美女天天色 | 爱色v| 青草视频在线观看免费资源 | 欧美3d怪物交videos网站 | 92国产福利视频一区二区 | 四虎精品视频在线永久免费观看 | 国产亚洲精品久久yy5099 | 亚洲一二区视频 | 日韩网新片免费 | 日韩中文字幕一区 | 久久午夜夜伦痒痒想咳嗽P 久久无码AV亚洲精品色午夜麻豆 | 天生奶水1v1高h |