日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

java 访问线程_java线程简介(共享对数据的访问)

發(fā)布時(shí)間:2024/9/19 编程问答 45 豆豆
生活随笔 收集整理的這篇文章主要介紹了 java 访问线程_java线程简介(共享对数据的访问) 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

1、 共享變量

要使多個(gè)線程在一個(gè)程序中有用,它們必須有某種方法可以互相通信或共享它們的結(jié)果。

讓線程共享其結(jié)果的最簡單方法是使用共享變量。它們還應(yīng)該使用同步來確保值從一個(gè)線程正確傳播到另一個(gè)線程,以及防止當(dāng)一個(gè)線程正在更新一些相關(guān)數(shù)據(jù)項(xiàng)時(shí),另一個(gè)線程看到不一致的中間結(jié)果。

線程基礎(chǔ)中計(jì)算素?cái)?shù)的示例使用了一個(gè)共享布爾變量,用于表示指定的時(shí)間段已經(jīng)過去了。這說明了在線程間共享數(shù)據(jù)最簡單的形式是:輪詢共享變量以查看另一個(gè)線程是否已經(jīng)完成執(zhí)行某項(xiàng)任務(wù)。

2、存在于同一個(gè)內(nèi)存空間中的所有線程

正如前面討論過的,線程與進(jìn)程有許多共同點(diǎn),不同的是線程與同一進(jìn)程中的其它線程共享相同的進(jìn)程上下文,包括內(nèi)存。這非常便利,但也有重大責(zé)任。只要訪問共享變量(靜態(tài)或?qū)嵗侄?,線程就可以方便地互相交換數(shù)據(jù),但線程還必須確保它們以受控的方式訪問共享變量,以免它們互相干擾對方的更改。

任何線程可以訪問所有其作用域內(nèi)的變量,就象主線程可以訪問該變量一樣。素?cái)?shù)示例使用了一個(gè)公用實(shí)例字段,叫做 finished,用于表示已經(jīng)過了指定的時(shí)間。當(dāng)計(jì)時(shí)器過期時(shí),一個(gè)線程會寫這個(gè)字段;另一個(gè)線程會定期讀取這個(gè)字段,以檢查它是否應(yīng)該停止。注:這個(gè)字段被聲明成 volatile,這對于這個(gè)程序的正確運(yùn)行非常重要。在本章的后面,我們將看到原因。

3、受控訪問的同步

為了確??梢栽诰€程之間以受控方式共享數(shù)據(jù),Java 語言提供了兩個(gè)關(guān)鍵字:synchronized 和 volatile。

Synchronized 有兩個(gè)重要含義:它確保了一次只有一個(gè)線程可以執(zhí)行代碼的受保護(hù)部分(互斥,mutual exclusion 或者說 mutex),而且它確保了一個(gè)線程更改的數(shù)據(jù)對于其它線程是可見的(更改的可見性)。

如果沒有同步,數(shù)據(jù)很容易就處于不一致狀態(tài)。例如,如果一個(gè)線程正在更新兩個(gè)相關(guān)值(比如,粒子的位置和速率),而另一個(gè)線程正在讀取這兩個(gè)值,有可能在第一個(gè)線程只寫了一個(gè)值,還沒有寫另一個(gè)值的時(shí)候,調(diào)度第二個(gè)線程運(yùn)行,這樣它就會看到一個(gè)舊值和一個(gè)新值。同步讓我們可以定義必須原子地運(yùn)行的代碼塊,這樣對于其他線程而言,它們要么都執(zhí)行,要么都不執(zhí)行。

同步的原子執(zhí)行或互斥方面類似于其它操作環(huán)境中的臨界段的概念。

4、確保共享數(shù)據(jù)更改的可見性

同步可以讓我們確保線程看到一致的內(nèi)存視圖。

處理器可以使用高速緩存加速對內(nèi)存的訪問(或者編譯器可以將值存儲到寄存器中以便進(jìn)行更快的訪問)。在一些多處理器體系結(jié)構(gòu)上,如果在一個(gè)處理器的高速緩存中修改了內(nèi)存位置,沒有必要讓其它處理器看到這一修改,直到刷新了寫入器的高速緩存并且使讀取器的高速緩存無效。

這表示在這樣的系統(tǒng)上,對于同一變量,在兩個(gè)不同處理器上執(zhí)行的兩個(gè)線程可能會看到兩個(gè)不同的值!這聽起來很嚇人,但它卻很常見。它只是表示在訪問其它線程使用或修改的數(shù)據(jù)時(shí),必須遵循某些規(guī)則。

Volatile 比同步更簡單,只適合于控制對基本變量(整數(shù)、布爾變量等)的單個(gè)實(shí)例的訪問。當(dāng)一個(gè)變量被聲明成 volatile,任何對該變量的寫操作都會繞過高速緩存,直接寫入主內(nèi)存,而任何對該變量的讀取也都繞過高速緩存,直接取自主內(nèi)存。這表示所有線程在任何時(shí)候看到的 volatile 變量值都相同。

如果沒有正確的同步,線程可能會看到舊的變量值,或者引起其它形式的數(shù)據(jù)損壞。

5、用鎖保護(hù)的原子代碼塊

Volatile 對于確保每個(gè)線程看到最新的變量值非常有用,但有時(shí)我們需要保護(hù)比較大的代碼片段,如涉及更新多個(gè)變量的片段。

同步使用監(jiān)控器(monitor)或鎖的概念,以協(xié)調(diào)對特定代碼塊的訪問。

每個(gè) Java 對象都有一個(gè)相關(guān)的鎖。同一時(shí)間只能有一個(gè)線程持有 Java 鎖。當(dāng)線程進(jìn)入 synchronized 代碼塊時(shí),線程會阻塞并等待,直到鎖可用,當(dāng)它可用時(shí),就會獲得這個(gè)鎖,然后執(zhí)行代碼塊。當(dāng)控制退出受保護(hù)的代碼塊時(shí),即到達(dá)了代碼塊末尾或者拋出了沒有在 synchronized 塊中捕獲的異常時(shí),它就會釋放該鎖。

這樣,每次只有一個(gè)線程可以執(zhí)行受給定監(jiān)控器保護(hù)的代碼塊。從其它線程的角度看,該代碼塊可以看作是原子的,它要么全部執(zhí)行,要么根本不執(zhí)行。

6、簡單的同步示例

使用 synchronized 塊可以讓您將一組相關(guān)更新作為一個(gè)集合來執(zhí)行,而不必?fù)?dān)心其它線程中斷或看到計(jì)算的中間結(jié)果。以下示例代碼將打印“1 0”或“0 1”。如果沒有同步,它還會打印“1 1”(或“0 0”,隨便您信不信)。

public class SyncExample {

private static lockObject = new Object();

private static class Thread1 extends Thread {

public void run() {

synchronized (lockObject) {

x = y = 0;

System.out.println(x);

}

}

}

private static class Thread2 extends Thread {

public void run() {

synchronized (lockObject) {

x = y = 1;

System.out.println(y);

}

}

}

public static void main(String[] args) {

new Thread1().run();

new Thread2().run();

}

}

在這兩個(gè)線程中都必須使用同步,以便使這個(gè)程序正確工作。

7、Java 鎖定

Java 鎖定合并了一種互斥形式。每次只有一個(gè)線程可以持有鎖。鎖用于保護(hù)代碼塊或整個(gè)方法,必須記住是鎖的身份保護(hù)了代碼塊,而不是代碼塊本身,這一點(diǎn)很重要。一個(gè)鎖可以保護(hù)許多代碼塊或方法。

反之,僅僅因?yàn)榇a塊由鎖保護(hù)并不表示兩個(gè)線程不能同時(shí)執(zhí)行該代碼塊。它只表示如果兩個(gè)線程正在等待相同的鎖,則它們不能同時(shí)執(zhí)行該代碼。

在以下示例中,兩個(gè)線程可以同時(shí)不受限制地執(zhí)行 setLastAccess() 中的 synchronized 塊,因?yàn)槊總€(gè)線程有一個(gè)不同的 thingie 值。因此,synchronized 代碼塊受到兩個(gè)正在執(zhí)行的線程中不同鎖的保護(hù)。

public class SyncExample {

public static class Thingie {

private Date lastAccess;

public synchronized void setLastAccess(Date date) {

this.lastAccess = date;

}

}

public static class MyThread extends Thread {

private Thingie thingie;

public MyThread(Thingie thingie) {

this.thingie = thingie;

}

public void run() {

thingie.setLastAccess(new Date());

}

}

public static void main() {

Thingie thingie1 = new Thingie(),

thingie2 = new Thingie();

new MyThread(thingie1).start();

new MyThread(thingie2).start();

}

}

8、同步的方法

創(chuàng)建 synchronized 塊的最簡單方法是將方法聲明成 synchronized。這表示在進(jìn)入方法主體之前,調(diào)用者必須獲得鎖:

public class Point {

public synchronized void setXY(int x, int y) {

this.x = x;

this.y = y;

}

}

對于普通的 synchronized方法,這個(gè)鎖是一個(gè)對象,將針對它調(diào)用方法。對于靜態(tài) synchronized 方法,這個(gè)鎖是與 Class 對象相關(guān)的監(jiān)控器,在該對象中聲明了方法。

僅僅因?yàn)?setXY() 被聲明成 synchronized 并不表示兩個(gè)不同的線程不能同時(shí)執(zhí)行 setXY(),只要它們調(diào)用不同的 Point 實(shí)例的 setXY() 就可同時(shí)執(zhí)行。對于一個(gè) Point 實(shí)例,一次只能有一個(gè)線程執(zhí)行 setXY(),或 Point 的任何其它 synchronized 方法。

9、同步的塊

synchronized 塊的語法比 synchronized 方法稍微復(fù)雜一點(diǎn),因?yàn)檫€需要顯式地指定鎖要保護(hù)哪個(gè)塊。Point 的以下版本等價(jià)于前一頁中顯示的版本:

public class Point {

public void setXY(int x, int y) {

synchronized (this) {

this.x = x;

this.y = y;

}

}

}

使用 this 引用作為鎖很常見,但這并不是必需的。這表示該代碼塊將與這個(gè)類中的 synchronized 方法使用同一個(gè)鎖。

由于同步防止了多個(gè)線程同時(shí)執(zhí)行一個(gè)代碼塊,因此性能上就有問題,即使是在單處理器系統(tǒng)上。最好在盡可能最小的需要保護(hù)的代碼塊上使用同步。

訪問局部(基于堆棧的)變量從來不需要受到保護(hù),因?yàn)樗鼈冎荒鼙蛔约核鶎俚木€程訪問。

10、大多數(shù)類并沒有同步

因?yàn)橥綍硇⌒〉男阅軗p失,大多數(shù)通用類,如 java.util 中的 Collection 類,不在內(nèi)部使用同步。這表示在沒有附加同步的情況下,不能在多個(gè)線程中使用諸如 HashMap 這樣的類。

總結(jié)

以上是生活随笔為你收集整理的java 访问线程_java线程简介(共享对数据的访问)的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。