當前位置 : IT培訓網 > Java開發 > Java教程 > 對Java線程同步的認識

對Java線程同步的認識

時間:2016-08-30 14:32:06??來源:Java培訓網??作者:IT培訓網??已有:名學員訪問該課程
同步的關鍵是管程(也叫信號量semaphore)的概念。管程是一個互斥獨占鎖定的對象,或稱互斥體(mutex)。在給定的時間,僅有一個線程可以獲得管程。當一個線程需要鎖定,它必須進入管程。所有其他的試圖進入已經鎖定的管程的

Java線程同步,是不是同時進行的意思呢,同時運行的意思呢,今天達內IT培訓網小編就來給大家詳細介紹一下吧!

我們可以在計算機上運行各種計算機軟件程序。每一個運行的程序可能包括多個獨立運行的線程(Thread)。

線程(Thread)是一份獨立運行的程序,有自己專用的運行棧。線程有可能和其他線程共享一些資源,比如,內存,文件,數據庫等。

當兩個或兩個以上的線程需要共享資源,它們需要某種方法來確定資源在某一刻僅被一個線程占用。達到此目的的過程叫做同步(synchronization)。像你所看到的,Java為此提供了獨特的,語言水平上的支持。

同步的關鍵是管程(也叫信號量semaphore)的概念。管程是一個互斥獨占鎖定的對象,或稱互斥體(mutex)。在給定的時間,僅有一個線程可以獲得管程。當一個線程需要鎖定,它必須進入管程。所有其他的試圖進入已經鎖定的管程的線程必須掛起直到第一個線程退出管程。這些其他的線程被稱為等待管程。一個擁有管程的線程如果愿意的話可以再次進入相同的管程。

如果你用其他語言例如C或C++時用到過同步,你會知道它用起來有一點詭異。這是因為很多語言它們自己不支持同步。相反,對同步線程,程序必須利用操作系統源語。幸運的是Java通過語言元素實現同步,大多數的與同步相關的復雜性都被消除。

你可以用兩種方法同步化代碼。兩者都包括synchronized關鍵字的運用,下面分別說明這兩種方法。

使用同步方法

Java中同步是簡單的,因為所有對象都有它們與之對應的隱式管程。進入某一對象的管程,就是調用被synchronized關鍵字修飾的方法。當一個線程在一個同步方法內部,所有試圖調用該方法(或其他同步方法)的同實例的其他線程必須等待。為了退出管程,并放棄對對象的控制權給其他等待的線程,擁有管程的線程僅需從同步方法中返回。

為理解同步的必要性,讓我們從一個應該使用同步卻沒有用的簡單例子開始。下面的程序有三個簡單類。首先是Callme,它有一個簡單的方法call( )。call( )方法有一個名為msg的String參數。該方法試圖在方括號內打印msg 字符串。有趣的事是在調用call( ) 打印左括號和msg字符串后,調用Thread.sleep(1000),該方法使當前線程暫停1秒。

下一個類的構造函數Caller,引用了Callme的一個實例以及一個String,它們被分別存在target 和 msg 中。構造函數也創建了一個調用該對象的run( )方法的新線程。該線程立即啟動。Caller類的run( )方法通過參數msg字符串調用Callme實例target的call( ) 方法。最后,Synch類由創建Callme的一個簡單實例和Caller的三個具有不同消息字符串的實例開始。

Callme的同一實例傳給每個Caller實例。

// This program is not synchronized.

class Callme {

void call(String msg) {

System.out.print("[" + msg);

try {

Thread.sleep(1000);

} catch(InterruptedException e) {

System.out.println("Interrupted");

}

System.out.println("]");

}

}

 

class Caller implements Runnable {

String msg;

Callme target;

Thread t;

public Caller(Callme targ, String s) {

target = targ;

msg = s;

t = new Thread(this);

t.start();

}

public void run() {

target.call(msg);

}

}

 

class Synch {

public static void main(String args[]) {

Callme target = new Callme();

Caller ob1 = new Caller(target, "Hello");

Caller ob2 = new Caller(target, "Synchronized");

Caller ob3 = new Caller(target, "World");

// wait for threads to end

try {

ob1.t.join();

ob2.t.join();

ob3.t.join();

} catch(InterruptedException e) {

System.out.println("Interrupted");

}

}

}

 

該程序的輸出如下:

Hello[Synchronized[World]

]

]

 

在本例中,通過調用sleep( ),call( )方法允許執行轉換到另一個線程。該結果是三個消息字符串的混合輸出。該程序中,沒有阻止三個線程同時調用同一對象的同一方法的方法存在。這是一種競爭,因為三個線程爭著完成方法。例題用sleep( )使該影響重復和明顯。在大多數情況,競爭是更為復雜和不可預知的,因為你不能確定何時上下文轉換會發生。這使程序時而運行正常時而出錯。

為達到上例所想達到的目的,必須有權連續的使用call( )。也就是說,在某一時刻,必須限制只有一個線程可以支配它。為此,你只需在call( ) 定義前加上關鍵字synchronized,如下:

class Callme {

synchronized void call(String msg) {

...

 

這防止了在一個線程使用call( )時其他線程進入call( )。在synchronized加到call( )前面以后,程序輸出如下:

[Hello]

[Synchronized]

[World]

 

任何時候在多線程情況下,你有一個方法或多個方法操縱對象的內部狀態,都必須用synchronized 關鍵字來防止狀態出現競爭。記住,一旦線程進入實例的同步方法,沒有其他線程可以進入相同實例的同步方法。然而,該實例的其他不同步方法卻仍然可以被調用。

同步語句

盡管在創建的類的內部創建同步方法是獲得同步的簡單和有效的方法,但它并非在任何時候都有效。這其中的原因,請跟著思考。假設你想獲得不為多線程訪問設計的類對象的同步訪問,也就是,該類沒有用到synchronized方法。而且,該類不是你自己,而是第三方創建的,你不能獲得它的源代碼。這樣,你不能在相關方法前加synchronized修飾符。怎樣才能使該類的一個對象同步化呢?很幸運,解決方法很簡單:你只需將對這個類定義的方法的調用放入一個synchronized塊內就可以了。

 

下面是synchronized語句的普通形式:

synchronized(object) {

// statements to be synchronized

}

 

其中,object是被同步對象的引用。如果你想要同步的只是一個語句,那么不需要花括號。一個同步塊確保對object成員方法的調用僅在當前線程成功進入object管程后發生。

下面是前面程序的修改版本,在run( )方法內用了同步塊:

// This program uses a synchronized block.

class Callme {

void call(String msg) {

System.out.print("[" + msg);

try {

Thread.sleep(1000);

} catch (InterruptedException e) {

System.out.println("Interrupted");

}

System.out.println("]");

}

}

 

class Caller implements Runnable {

String msg;

Callme target;

Thread t;

public Caller(Callme targ, String s) {

target = targ;

msg = s;

t = new Thread(this);

t.start();

}

 

// synchronize calls to call()

public void run() {

synchronized(target) { // synchronized block

target.call(msg);

}

}

}

 

class Synch1 {

public static void main(String args[]) {

Callme target = new Callme();

Caller ob1 = new Caller(target, "Hello");

Caller ob2 = new Caller(target, "Synchronized");

Caller ob3 = new Caller(target, "World");

 

// wait for threads to end

try {

ob1.t.join();

ob2.t.join();

ob3.t.join();

} catch(InterruptedException e) {

System.out.println("Interrupted");

}

}

}

 

這里,call( )方法沒有被synchronized修飾。而synchronized是在Caller類的run( )方法中聲明的。這可以得到上例中同樣正確的結果,因為每個線程運行前都等待先前的一個線程結束。

關于Java線程同步的知識點就介紹到這里了,無論大家是否學會了,都不要忘記,知識是無窮盡的,活到老學到老,如果想要接受更多新知識,還需要關注達內IT培訓網哦!

頂一下
(0)
0%
踩一下
(0)
0%
------分隔線----------------------------
------分隔線----------------------------
Java教程
1、Java 概述
1.1 Java語言概述
1.2 Java虛擬機以及跨平臺原理
1.3 Java的主要就業方向
1.4 Java的不同版本
1.5 Java開發環境搭建
1.6 第一個Java程序示例
1.7 Java類和對象的概念
1.8 Java類庫及其組織結構
1.9 Java import
2、Java 語法基礎
2.1 Java數據類型以及變量的定義
2.2 Java數據類型轉換
2.3 Java運算符
2.4 Java流程控制
2.5 Java數組的定義和使用
2.6 Java字符串(String)
2.7 Java StringBuffer與StringBuider
2.8 強調一下編程風格
3、Java 類與對象
3.1 Java類的定義及其實例化
3.2 Java訪問修飾符
3.3 Java變量的作用域
3.4 Java this關鍵字詳解
3.5 Java方法重載
3.6 Java類的基本運行順序
3.7 Java包裝類、拆箱和裝箱詳解
3.8 再談Java包
3.9 源文件的聲明規則
4、Java 繼承和多態
4.1 繼承的概念與實現
4.2 Java super關鍵字
4.3 繼承中的方法的覆蓋和重載
4.4 多態和動態綁定
4.5 instanceof 運算符
4.6 多態對象的類型轉換
4.7 Java static關鍵字
4.8 Java final關鍵字
4.9 Java Object類
5、面向對象高級特性
5.1 Java內部類及其實例化
5.2 內部類的分類
5.3 抽象類的概念和使用
5.4 接口的概念和使用
5.5 接口和抽象類的區別
5.6 Java 泛型
5.7 泛型通配符和類型參數的范圍
6、異常處理
6.1 異常處理基礎
6.2 異常類型Java語言中常見的異常類型有哪些
6.3 未被捕獲的異常
6.4 try和catch的使用
6.5 多重catch語句的使用
6.6 try語句的嵌套
6.7 throw:異常的拋出
6.8 throws子句
6.9 finally塊
6.10 Java的內置異常
6.11 創建自己的異常子類
6.12 斷言
7、線程編程
7.1 線程的概念
7.2 Java線程模型
7.3 主線程
7.4 創建線程
7.5 創建多線程
7.6 isAlive()和join()的使用
7.7 線程優先級
7.8 線程同步
7.9 線程間通信
7.10 線程死鎖
7.11 線程的掛起、恢復和終止
8、輸入輸出(IO)操作
8.1 輸入輸出基本概念
8.2 面向字符的輸入流
8.3 面向字符的輸出流
8.4 面向字節的輸入輸出流
8.5 面向字節流的應用
8.6 文件與目錄管理
8.7 文件的隨機讀寫
8.8 文件的壓縮處理
9、常用類庫、向量與哈希
9.1 Java基礎類庫
9.2 Object類
9.3 Java語言包(java.lang)簡介
9.4 日期和時間類
9.5 向量及其應用
9.6 哈希表及其應用
10、圖形界面(GUI)設計
10.1 圖形界面設計基礎
10.2 框架窗口
10.3 標簽、按鈕和按鈕事件
10.4 面板
10.5 布局設計
10.6 文本框和文本區
10.7 文本框和文本區的輸入輸出
10.8 選擇框和單選按鈕
10.9 列表和組合框
10.10 菜單
10.11 對話框
10.12 滾動條
10.13 鼠標事件
10.14 鍵盤事件
11、圖形、圖像與多媒體
11.1 繪圖基礎
11.2 設置字型和顏色
11.3 繪圖模式
11.4 Graphics類的繪圖方法
11.5 Graphics2D類的繪圖方法
11.6 圖像處理基礎
11.7 圖像緩沖技術
11.8 多媒體基礎
12、網絡與數據庫編程
12.1 IP地址和InetAddress類
12.2 統一資源定位符
12.3 套接字(Socket)
12.4 數據庫連接
12.5 幾個重要的類和接口
12.6 數據庫查詢
12.7 數據庫更新
12.8 插入記錄
12.9 修改記錄
12.10 刪除記錄
激情色播