夜光:Java成神之路(十)擅長的語言

夜光序言:

 

在慾望,性命,血漿裏窺探命運,早晚都會被天道輪迴所反噬。

不是你的東西,終究不是。

 

 

 

 

 
 
正文:
 
                                              以道御術 / 以術識道



補充:上面兩種方式的組合:將共享數據封裝在另外一個對象中,每個線程對共享數據的操作方法也分配到那個對象身上去完成,對象作爲這個外部類中的成員變量或方法中的局部變量,每個線程的 Runnable 對象
 
作爲外部類中的成員內部類或局部內部類。
 
總之,要同步互斥的幾段代碼最好是分別放在幾個獨立的方法中,這些方法再放在同一個類中,這樣比較容 易實現它們之間的同步互斥和通信。

 

這個需要看下上一章,謝謝

 

(二)多線程基礎知識--線程併發庫

Java 5 添加了一個新的包到 Java 平臺,java.util.concurrent 包。
 
這個包包含有一系列能夠讓 Java 的併發編程變得更加簡單輕鬆的類。
 
在這個包被添加以前,你需要自己去動手實現自己的相關工具類。
 
 
下面帶你認識下 java.util.concurrent 包裏的這些類,然後你可以嘗試着如何在項目中使用它們。
 
本文中將使用 Java 6 版本,我不確定這和 Java 5 版本里的是否有一些差異。我不會去解釋關於 Java 併發的核心問題 – 其背後的原理

 


( 1 ) Java 的線程併發庫介紹

 
 
Java5 的多線程並有兩個大發庫在 java.util.concurrent 包及子包中,子包主要的包有一下兩個
 

1) java.util.concurrent 包 (多線程併發庫)

 
java.util.concurrent 包含許多線程安全、測試良好、高性能的併發構建塊
 
不客氣地說,創建java.util.concurrent 的目的就是要實現 Collection 框架對數據結構所執行的併發操作。
 
通過提供一組可靠的、 高性能併發構建塊,開發人員可以提高併發類的線程安全、可伸縮性、性能、可讀性和可靠性,後面、我們會做介紹。
 
如果一些類名看起來相似,可能是因爲 java.util.concurrent 中的許多概念源自 Doug Lea 的 util.concurrent 庫。

 

 

2) java.util.concurrent.atomic 包 (多線程的原子性操作提供的工具類)

 
查看 atomic 包文檔頁下面的介紹,它可以對多線程的基本數據、數組中的基本數據和對象中的基本數據進行多線程的操作(AtomicInteger、AtomicIntegerArray、AtomicIntegerFieldUpDater…)
 
通過如下兩個方法快速理解 atomic 包的意義:
 
  AtomicInteger 類的 boolean compareAndSet(expectedValue, updateValue);
  AtomicIntegerArray 類的 int addAndGet(int i, int delta);
 
順帶解釋 volatile 類型的作用,需要查看 java 語言規範
 
  volatile 修飾的變量,線程在每次使用變量的時候,都會讀取變量修改後的最的值。(具有可見性)
  volatile 沒有原子性。
 
 

3) java.util.concurrent.lock 包 (多線程的鎖機制)

爲鎖和等待條件提供一個框架的接口和類,它不同於內置同步和監視器。該框架允許更靈活地使用鎖和條件。

 

本包下有三大接口,下面簡單介紹下:

 
Lock 接口:支持那些語義不同(重入、公平等)的鎖規則,可以在非阻塞式結構的上下文(包括 handover-hand 和鎖重排算法)中使用這些規則。
 

主要的實現是 ReentrantLock。

 
ReadWriteLock 接口:以類似方式定義了一些讀取者可以共享而寫入者獨佔的鎖。
此包只提供了一個實現,ReentrantReadWriteLock,因爲它適用於大部分的標準用法上下文。
 

但程序員可以創建自己的、 適用於非標準要求的實現。

 
 
➢Condition 接口:描述了可能會與鎖有關聯的條件變量。
 
這些變量在用法上與使用 Object.wait 訪問的隱式監視器類似,但提供了更強大的功能。
 
需要特別指出的是,單個 Lock 可能與多個 Condition 對象關聯。
 
爲了避免兼容性問題,Condition 方法的名稱與對應的 Object 版本中的不同。

 


 
( 2 ) Java 的併發庫入門
 

下面我們將分別介紹 java.util.concurrent 包下的常用類的使用。

 
1)  java.util.concurrent 包
 
java.util.concurrent 包描述:
在併發編程中很常用的實用工具類。
此包包括了幾個小的、已標準化的可擴展框架,以及一些提供有用功能的類。
 
此包下有一些組件,其中包括:
 
  執行程序(線程池)
  併發隊列
  同步器
  併發 Collocation
 

 


下面我們將 java.util.concurrent 包下的組件逐一簡單介紹:

 

A. 執行程序

Executors 線程池工廠類

 
首次我們來說下線程池的作用:
 
線程池作用就是限制系統中執行線程的數量。
 
根據系統的環境情況,可以自動或手動設置線程數量,達到運行的最佳效果;少了浪費了系統資源,多了造成系統擁擠效率不高。
 

用線程池控制線程數量,其他線程 排隊等候。

 
一個任務執行完畢,再從隊列的中取最前面的任務開始執行。若隊列中沒有等待進程,線程池的這一資源處於等待。當一個新任務需要運行時,如果線程 池中有等待的工作線程,就可以開始運行了;否則進入等待隊列。
 

爲什麼要用線程池:

  減少了創建和銷燬線程的次數,每個工作線程都可以被重複利用,可執行多個任務
  可以根據系統的承受能力,調整線程池中工作線線程的數目,防止因爲因爲消耗過多的內存,而把服務器累趴下(每個線程需要大約 1MB 內存,線程開的越多,消耗的內存也就越大,最後死機)
 

 

Executors 詳解:

 

 

Java 裏面線程池的頂級接口是 Executor,但是嚴格意義上講 Executor 並不是一個線程池,而只是一個執行線程的工具。

 
真正的線程池接口是 ExecutorService。ThreadPoolExecutor 是 Executors 類的底層實現。
 
 
我們先介紹下 Executors。
 
線程池的基本思想還是一種對象池的思想,開闢一塊內存空間,裏面存放了衆多(未死亡)的線程,池中線程執行調度由池管理器來處理。
 
 
當有線程任務時,從池中取一個,執行完成後線程對象歸池,這樣可以避免反復創建線程對象所帶來的性能開銷,節省了系統的資源。
 
 

 

Java5 中併發庫中,線程池創建線程大致可以分爲下面三種:

 

//創建固定大小的線程池
ExecutorService fPool = Executors.newFixedThreadPool(3);
//創建緩存大小的線程池
ExecutorService cPool = Executors.newCachedThreadPool();
//創建單一的線程池
ExecutorService sPool = Executors.newSingleThreadExecutor();

下面我們通過簡單示例來分別說明:

 
 
 
固定大小連接池
 
package com.hy.多線程高併發;

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class Test8 {
    public static void main(String[] args) {
        //創建一個可重用固定線程數的線程池
        ExecutorService pool = Executors.newFixedThreadPool(2);
        //創建實現了 Runnable 接口對象,Thread 對象當然也實現了 Runnable 接口
        Thread t1 = new MyThread();
        Thread t2 = new MyThread();
        Thread t3 = new MyThread();
        Thread t4 = new MyThread();
        Thread t5 = new MyThread();
        //將線程放入池中進行執行
        pool.execute(t1);
        pool.execute(t2);
        pool.execute(t3);
        pool.execute(t4);
        pool.execute(t5);
        //關閉線程池
        pool.shutdown();
    }
}


class MyThread extends Thread{
    @Override
    public void run() {
        System.out.println(Thread.currentThread().getName()+"正在執行。。。");
    }
}

 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章