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

服務器之家:專注于服務器技術及軟件下載分享
分類導航

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

服務器之家 - 編程語言 - Java教程 - 深入講解java線程與synchronized關鍵字

深入講解java線程與synchronized關鍵字

2020-08-25 11:16Walker_YAM Java教程

Java 中多線程的同步依靠的是對象鎖機制,synchronized關鍵字就是利用了封裝對象鎖來實現對共享資源的互斥訪問。下面這篇文章主要介紹了java線程與synchronized關鍵字的相關資料,需要的朋友可以參考下。

我們將會從以下的幾點理解java線程的一些概念:

  1. 線程的基本概念和優劣之處
  2. 創建一個線程的兩種方式
  3. 線程的屬性
  4. 線程的狀態
  5. synchronized可修飾的方法
  6. synchronized的重要特性

一、線程的基本概念

在計算機中有進程和線程這么兩個概念,進程中可以有多個線程,它們是從屬關系,進程往往更像是資源的占有者,線程才是程序的執行者,多個線程之間共享著進程中的資源。一個cpu同時只能運行一個線程,每個線程都有一個時間片,時間片用完了就會被阻塞并讓出CPU的控制權,交給下一個線程使用。這樣在計算機中就可以實現多任務的假象,其實CPU在不斷的切換線程,好像多個任務在同時運行。

使用線程的優勢毋庸置疑,可以增加CPU的執行效率,一旦某個線程需要等待某種資源(例如:等待打印機),就可以將它阻塞釋放CPU讓CPU執行別的線程,而不需要讓CPU和此線程一起等待某種資源從而提高系統效率,另外一點就是可以用這種假象增加用戶體驗度。但是,CPU在切換不同線程之間所要花費的代價也是不可忽視的,在較為復雜的程序中這種劣勢可能九流一毛,但是如果在簡單的程序中就會顯得尤為突出。

二、創建一個線程

接下來我們看看如何在java中創建一個線程來實現多個線程同時運行。第一種方式,java 中有一個類Thread,我們只要繼承這個類并重寫他的run方法,調用start方法就可以啟動一個新的線程了。(沒見過的同學可能不能理解以下代碼,下面我會解釋)

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
/*聲明自己的一個線程類*/
public class Test_thread extends Thread {
 //重寫Thread類中的run方法
 public void run(){
 System.out.println("i am the thread");
 }
}
 
public class Test_Class {
 public static void main(String[] args){
 Test_thread thread = new Test_thread();
 thread.start();
 }
}

輸出結果:i am the thread

首先我們先了解一下,一個線程被創建之后,怎么才能啟動運行,我們調用thread.start();方法啟動一個線程,首先就會執行我們重寫的run方法(如果沒有重寫就會調用Thread類的run方法,什么也不做,這也是我們重寫run方法的原因),也就是說run方法是一個線程的開始。有個疑問,為什么調用start方法,卻執行了run方法了?其實調用start方法就是為線程的啟動做準備操作,分配線程私有的堆棧資源,然后執行run方法。

下面我們看創建一個線程的第二種方式,實現接口Runnable,并重寫其中的run方法。

?
1
2
3
4
5
6
7
8
9
10
11
12
public class Test_thread implements Runnable {
 public void run(){
  System.out.println("i am the thread");
 }
}
 
public class Test_Class {
 public static void main(String[] args){
  Test_thread thread = new Test_thread();
  thread.start();//編譯錯誤
 }
}

我們會發現雖然重寫了run方法,但是在調用start方法的時候卻編譯錯誤,我們進入到Runnable接口的源代碼中可以看到,只有一個抽象方法run,所以沒有啟動線程的start方法,所以我們還是要借助Tread類。

?
1
2
3
4
5
6
public class Test_Class {
 public static void main(String[] args){
  Thread thread = new Thread(new Test_thread());
  thread.start();
 }
}

因為Thread類中有start方法,所以可以使用Thread的一個構造函數傳入一個實現了Runnable接口的類型,構建一個Thread類。

三、線程的屬性和狀態

在一個多線程的程序中我們使用線程的一些屬性來區別和辨認它們:

?
1
2
3
4
5
6
private long tid;
private volatile char name[];
public static native Thread currentThread()
private boolean  daemon = false;
private volatile int threadStatus = 0;
public final static int NORM_PRIORITY = 5;

每個線程會有一個tid指定此線程的在所有線程中的排序,這個值是遞增的,還有一個name指定該線程的名字,也可以使用setName設置一個優雅的線程名字,Thread類還提供了一個方法返回當前正在占用CPU的線程對象。每個線程在某個時刻都是有狀態的,屬性threadStatus記錄了當前對象線程的狀態是什么,默認情況下,所有的線程的優先級都被置為5,如果有特殊需要可以修改線程的優先級,使得某個線程可以優先得到運行。下面介紹線程的幾種不同的狀態。

  1. New:線程剛剛被創建,還沒有被啟動。
  2. Runnable:線程處于可運行的狀態,但是不一定處于正在運行的狀態(后面解釋區別)
  3. Blocked:線程處于被阻塞的狀態,一般是請求某資源不成功于是讓出CPU阻塞自己(具體的區別后面說)
  4. Waiting:線程處于等待狀態,一般是等待服務
  5. Terminated:線程終止,也就是線程被kill,釋放其占用的資源

下面具體的說說不同狀態下的線程的一些操作,首先看看new,線程從此被創建,只是離運行狀態還需要一些準備。Runnable表示線程是可運行,至于是否已經處于運行狀態還要看系統給的時間片是否用完,如果用完了就會將此線程放置在可運行線程隊列的尾部,等待下次分配時間片,如果時間片沒有用完,就是處于運行狀態的(這也是為什么叫做Runnable而不是Running的原因)。接下來的兩種狀態Blocked和waiting都表示線程阻塞,需要讓出CPU。只是導致它們處于這種狀態的原因不一樣,具體的在我們介紹完synchronized關鍵字之后就會不言而喻了。

四、關鍵字synchronized

先看一段代碼:

?
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
public class Test_thread extends Thread{
 public static int count = 0;
 public void run(){
  try {
   Thread.sleep((int) (Math.random() * 100));
  }catch(InterruptedException e){
 
  }
  count++;
 }
}
 
public class Test_Class {
 public static void main(String[] args){
  Test_thread[] thread = new Test_thread[1000];
  for(int a=0;a<1000;a++){
   thread[a] = new Test_thread();
   thread[a].start();
  }
 
  for(int a=0;a<1000;a++){
   try {
    thread[a].join();
   }catch (InterruptedException e){
 
   }
  }
  System.out.println(Test_thread.count);
 }
}

按照直覺,創建1000個線程,每個線程隨機睡覺并將公共變量增一,main線程等待所有線程執行結束之后,輸出公共變量的值。按照直覺答案應該是1000,但是我們運行的結果每次都是不一樣的,接近1000但每次都不一樣。這是為什么呢?這其實就是簡單的模擬了高并發,可能有幾個線程睡了相同的時間,同時醒來獲取的count值是相同的,這就導致這幾個線程對count的操作被覆蓋了。

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
public class Test_thread extends Thread{
 public static int count = 0;
 public void run(){
  try {
   Thread.sleep((int) (Math.random() * 100));
  }catch(InterruptedException e){
 
  }
  /*使用關鍵字*/
  synchronized (Test_thread.class){
   count++;
  }
 }
}

一個簡單的關鍵字就可以輕松解決這樣的高并發的問題。至于為什么這么寫?在介紹完synchronized關鍵字之后,想必你就會知道了。

首先我們需要知道,每個對象都有一把內部鎖。所以被synchronized關鍵字修飾的方法,其實是被加了內部對象鎖。我們看代碼:

?
1
2
3
4
5
6
7
8
public class Counter{
 private int count;
 
 /*為實例方法加此關鍵字*/
 public synchronized int getCount(){
  return count;
 }
}

為實例方法添加關鍵字,實際上就是給當前的對象加鎖;括號中就是要加鎖的對象。

?
1
2
3
4
5
6
7
8
public class Counter{
 private int count;
 
 /*為實例方法加此關鍵字*/
 synchronized(this){
  return count;
 }
}

對于靜態方法,實際上就是為這個類加上鎖;

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
  public class Counter{
  private static int count;
 
  public static synchronized int getCount(){
   return count;
  }
 }
 
/*實際上給這個類加上鎖*/
 public class Counter{
  private int count;
 
  synchronized(Counter.class){
   return count;
  }
 }

五、深入理解synchronized的一些特性

第一個性質是:可重入性。被synchronized修飾的方法中的所有操作都是原子操作,但是當我們需要在其中訪問另外的一些需要鎖的代碼時候,可以直接獲取別的鎖。也就是當前的對象是可以獲得多個鎖的。

第二個性質是:內存的可見性。在我們的計算機中,其實有很多的操作并不是很"干脆"的,比如你向數據庫中存數據時,其實很多時候一些待存入的數據積累在緩存中等到一定數據量的時候才會統一的存入數據庫,但是在我們看來這些數據其實應該早就存入數據庫了。這就導致了一個內存的不可見性問題。當然我們也是可以使用關鍵字synchronized來保證每次取出的數據都是最新的。在釋放鎖的時候會立即將數據協會內存,獲得鎖的時候會去讀取最新的內容。

?
1
2
3
4
5
6
7
8
public class Counter{
 private int count;
 
 public synchronized int getCount(){
  return count;
 }
}
/*每次獲得該對象的鎖之后,去獲取最新的count數值*/

其實,如果僅僅是要保證內存的不可見性,使用synchronized關鍵字可能代價有點高,在這種情況下,我們可以使用關鍵字volatile。

?
1
2
3
4
5
6
7
8
9
public class Counter{
 /*使用關鍵字volatile*/
 private volatile int count;
 
 public int getCount(){
  return count;
 }
}
/*此關鍵字保證每次使用count的時候數據都是最新的*/

總結

以上就是這篇文章的全部內容了,還是希望大家發現其中錯誤直接指出,方便我糾正錯誤,更新知識。java并發系列文章,希望大家多多關注。

原文鏈接:http://www.cnblogs.com/yangming1996/p/6515830.html

延伸 · 閱讀

精彩推薦
主站蜘蛛池模板: 99在线视频精品费观看视 | 九九爱这里只有精品 | 国产亚洲一级精品久久 | 久久婷婷电影网 | 亚洲国产精品无圣光一区二区 | 亚洲视频日韩 | 国产大片51精品免费观看 | 精品综合一区二区三区 | 192.168.191| 精品一区二区三区中文 | 高h辣文小说网 烧书阁 | 美女的让男人桶爽网站 | 免看一级一片一在线看 | 国产精品高清一区二区三区不卡 | 精品国产mmd在线观看 | 欧美日韩国产亚洲一区二区 | 调教全程肉动画片在线观看 | 草逼的视频 | 波多野给衣一区二区三区 | 8x8x拔插| 韩国久久精品 | 楚乔传第二部免费完整 | 四虎精品视频在线永久免费观看 | 俺不色| 精彩国产萝视频在线 | 日本免费高清在线观看播放 | 国产亚洲综合久久 | 香蕉久久一区二区三区啪啪 | 关晓彤被调教出奶水的视频 | 亚洲va在线va天堂va偷拍 | 精品视频一区二区观看 | 被夫上司侵犯了中文字幕 | 国产一区二区三区福利 | 免费的伦理片 | ova巨公主催眠1在线观看 | 2020国产精品亚洲综合网 | 免费一级欧美片在线观看 | 免费观看视频高清在线 | 好男人资源在线观看免费的 | 免费又爽又黄禁片视频在线播放 | 亚州人成网在线播放 |