聯系博主          博客地圖
                     
                 看了文章一,應該對線程有個初步的認識了,我再簡單的介紹一下線程使用中的一些內容.
          線程通過幾種機制進入 Java 程序。除了用 Thread 構造器中顯式創建線程之外,還可以用許多其它機制創建線程:
          · AWT 和 Swing
          · RMI
          · java.util.TimerTask 工具
          · servlet 和 JSP 技術
          我只是簡單的提一下后兩種.
          TimerTask.
          JDK 1.3 中,TimerTask 工具被引入到 Java 語言。這個便利的工具讓您可以稍后在某個時間執行任務(例如,即從現在起十秒后運行一次任務),或者定期執行任務(即,每隔十秒運行任務)。
          實現 Timer 類非常簡單:它創建一個計時器線程,并且構建一個按執行時間排序的等待事件隊列。
          TimerTask 線程被標記成守護程序線程,這樣它就不會阻止程序退出。
          servlet 容器創建多個線程,在這些線程中執行 servlet 請求。作為 servlet 編寫者,您不知道(也不應該知道)您的請求會在什么線程中執行;如果同時有多個對相同 URL 的請求入站,那么同一個 servlet 可能會同時在多個線程中是活動的。
          當編寫 servlet 或 JavaServer Pages (JSP) 文件時,必須始終假設可以在多個線程中并發地執行同一個 servlet 或 JSP 文件。必須適當同步 servlet 或 JSP 文件訪問的任何共享數據;這包括servlet 對象本身的字段。
          下面說一下共享數據的訪問,這也是線程的一個很重要的部分.
          要使多個線程在一個程序中有用,它們必須有某種方法可以互相通信或共享它們的結果。
          讓線程共享其結果的最簡單方法是使用共享變量。它們還應該使用同步來確保值從一個線程正確傳播到另一個線程,以及防止當一個線程正在更新一些相關數據項時,另一個線程看到不一致的中間結果。有關兩個關鍵字:synchronized 和volatile以及java鎖,我已經在上一篇文章里面提到了,這里我再深入的介紹一下.
          先復述一下java鎖,
          每個 Java 對象都有一個相關的鎖。同一時間只能有一個線程持有 Java 鎖。當線程進入
          synchronized 代碼塊時,線程會阻塞并等待,直到鎖可用,當它可用時,就會獲得這個鎖,然后執行代碼塊。當控制退出受保護的代碼塊時,即到達了代碼塊末尾或者拋出了沒有在 synchronized 塊中捕獲的異常時,它就會釋放該鎖。
          Java 鎖定合并了一種互斥形式。每次只有一個線程可以持有鎖。鎖用于保護代碼塊或整個方法,必須記住是鎖的身份保護了代碼塊,而不是代碼塊本身,這一點很重要。一個鎖可以保護許多代碼塊或方法。
          反之,僅僅因為代碼塊由鎖保護并不表示兩個線程不能同時執行該代碼塊。它只表示如果兩個線程正在等待相同的鎖,則它們不能同時執行該代碼。
          下面這個實例代碼展示就是后面這種情況. ,兩個線程可以同時不受限制地執行 setLastAccess() 中的 synchronized 塊,因為每個線程有一個不同的 thingie 值。因此,synchronized 代碼塊受到兩個正在執行的線程中不同鎖的保護。
          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();
          }
          }
          同步方法
          創建 synchronized 塊的最簡單方法是將方法聲明成 synchronized。這表示在進入方法主體之前,
          調用者必須獲得鎖:
          public class Point {
          public synchronized void setXY(int x, int y) {
          this.x = x;
          this.y = y;
          }
          }
          對于普通的 synchronized 方法,這個鎖是一個對象,將針對它調用方法。對于靜態 synchronized方法,這個鎖是與 Class 對象相關的監控器,在該對象中聲明了方法。
          僅僅因為 setXY() 被聲明成 synchronized 并不表示兩個不同的線程不能同時執行 setXY(),只要它們調用不同的 Point 實例的 setXY() 就可同時執行。對于一個 Point 實例,一次只能有一個線程執行 setXY(),或 Point 的任何其它 synchronized 方法。
          如以下代碼樣本所示,SimpleCache.java 使用 HashMap 為對象裝入器提供了一個簡單的高速緩存。
          load() 方法知道怎樣按對象的鍵裝入對象。在一次裝入對象之后,該對象就被存儲到高速緩存中,這樣以后的訪問就會從高速緩存中檢索它,而不是每次都全部地裝入它。對共享高速緩存的每個訪問都受到 synchronized 塊保護。由于它被正確同步,所以多個線程可以同時調用 getObject 和clearCache 方法,而沒有數據損壞的風險。
          public class SimpleCache {
          private final Map cache = new HashMap();
          public Object load(String objectName) {
          // load the object somehow
          }
          public void clearCache() {
          synchronized (cache) {
          cache.clear();
          }
          }
          public Object getObject(String objectName) {
          synchronized (cache) {
          Object o = cache.get(objectName);
          if (o == null) {
          o = load(objectName);
          cache.put(objectName, o);
          }
          }
          return o;
          }
          }
          由于線程執行的計時是不確定的,我們需要小心,以控制線程對共享數據的訪問。否則,多個并發線程會互相干擾對方的更改,從而損壞數據,或者其它線程也許不能及時看到對共享數據的更改。通過使用同步來保護對共享變量的訪問,我們可以確保線程以可預料的方式與程序變量進行交互。每個 Java 對象都可以充當鎖,synchronized 塊可以確保一次只有一個線程執行由給定鎖保護的synchronized 代碼。
          那么什么時候需要使用同步呢?
          要跨線程維護正確的可見性,只要在幾個線程之間共享非 final 變量,就必須使用 synchronized(或 volatile)以確保一個線程可以看見另一個線程做的更改。
          可見性同步的基本規則是在以下情況中必須同步:
          · 讀取上一次可能是由另一個線程寫入的變量
          · 寫入下一次可能由另一個線程讀取的變量
          許多 Java 類,包括 String、Integer 和 BigDecimal,都是不可改變的:一旦構造之后,它們的狀態就永遠不會更改。如果某個類的所有字段都被聲明成 final,那么這個類就是不可改變的。(實際上,許多不可改變的類都有非 final 字段,用于高速緩存以前計算的方法結果,如String.hashCode(),但調用者看不到這些字段。)不可改變的類使并發編程變得非常簡單。因為不能更改它們的字段,所以就不需要擔心把狀態的更
          改從一個線程傳遞到另一個線程。在正確構造了對象之后,可以把它看作是常量。
          同樣,final 字段對于線程也更友好。因為 final 字段在初始化之后,它們的值就不能更改,所以當在線程之間共享 final 字段時,不需要擔心同步訪問。
          什么時候不需要同步呢?
          在某些情況中,您不必用同步來將數據從一個線程傳遞到另一個,因為 JVM 已經隱含地為您執行同步。這些情況包括:
          · 由靜態初始化器(在靜態字段上或 static{} 塊中的初始化器)初始化數據時
          · 訪問 final 字段時
          · 在創建線程之前創建對象時
          · 線程可以看見它將要處理的對象時
          再介紹一個概念,死鎖.
          只要您擁有多個進程,而且它們要爭用對多個鎖的獨占訪問,那么就有可能發生死鎖。如果有一組進程或線程,其中每個都在等待一個只有其它進程或線程才可以執行的操作,那么就稱它們被死鎖了。
          最常見的死鎖形式是當線程 1 持有對象 A 上的鎖,而且正在等待與 B 上的鎖,而線程 2 持有對象 B 上的鎖,卻正在等待對象 A 上的鎖。這兩個線程永遠都不會獲得第二個鎖,或者釋放第一個鎖。它們只會永遠等待下去。要避免死鎖,應該確保在獲取多個鎖時,在所有的線程中都以相同的順序獲取鎖。
          同步準則
          當編寫 synchronized 塊時,有幾個簡單的準則可以遵循,這些準則在避免死鎖和性能危險的風險方面大有幫助:
          代碼塊要簡短Synchronized 塊應該簡短 — 在保證相關數據操作的完整性的同時,
          盡量簡短。把不隨線程變化的預處理和后處理移出 synchronized 塊。
          不要阻塞。不要在 synchronized 塊或方法中調用可能引起阻塞的方法,如
          則呢arInputStream.read()。
          在持有鎖的時候,不要對其它對象調用方法。這聽起來可能有些極端,但它消除了最常見的死鎖源頭。
          有關線程的編程還有很多內容,我只是介紹一個初級的入門知識,我也是才學習線程了,文章主要內容是根據網上流傳的資料改變整理.

              核心: 勇敢進取年輕的心

           


          只有注冊用戶登錄后才能發表評論。


          網站導航:
           

          Copyright © 怎么羨慕天空的飛鳥

          主站蜘蛛池模板: 盐池县| 县级市| 饶阳县| 吉水县| 宁城县| 古浪县| 鲁甸县| 边坝县| 武山县| 威海市| 北碚区| 英吉沙县| 庐江县| 绥棱县| 科尔| 平乐县| 北碚区| 定安县| 南木林县| 祥云县| 广元市| 绥滨县| 湾仔区| 竹溪县| 扎鲁特旗| 龙游县| 双流县| 喀喇沁旗| 措美县| 平远县| 读书| 丽水市| 平果县| 徐汇区| 连山| 巴彦淖尔市| 志丹县| 朝阳区| 密云县| 灵武市| 鄂伦春自治旗|