---------------------- android培訓、java培訓、期待與您交流! ----------------------
5.多個線程訪問共享對象和數據的方式
如果每個線程執行的代碼相同,可以使用同一個Runnable對象,這個Runnable
對象中有那個共享數據。
如果每個線程執行的代碼不同,這時候需要用不同的Runnable對象,這時可以將共
享數據封裝在另外一個對象中,然後將這個對象逐一傳遞給各個Runnable對象。每
個線程對共享數據的操作方法也分配到那個對象身上去完成(把數據和數據操作封裝
在一起),這樣容易實現針對該數據進行的各個操作的互斥和通信。
多個線程訪問共享對象和數據時,數據容易出現安全問題,因此,要注意加鎖。
6.線程池的概念:首先創建一些線程,它們的集合稱爲線程池,當服務器接受到一個客戶請求後,就從線程池中取出一個空閒的線程爲之服務,服務完後不關閉該線程,而是將該線程還回到線程池中。
在線程池的編程模式下,任務是提交給整個線程池,而不是直接交給某個線程,線程池在拿到任務後,它就在內部找有無空閒的線程,再把任務交給內部某個空閒的線程,若無空閒線程,則任務處於等待狀態。記住,任務是提交給整個線程池,一個線程同時只能執行一個任務,但可以同時向一個線程池提交多個任務。
Executors工廠類才產生線程池,相關方法(部分)如下:
static ExecutorService newCachedThreadPool()
創建一個可根據需要創建新線程的線程池,但是在以前構造的線程可用時將重用它們。
static ExecutorService newFixedThreadPool(int nThreads)
創建一個可重用固定線程數的線程池。
static ScheduledExecutorServicenewScheduledThreadPool(int nThreads)
創建一個可重用固定線程數的線程池,它可安排在給定延遲後運行或者定期地執行。
static ExecutorService newSingleThreadExecutor()
創建一個只有一個線程的線程池,相當於newFixedThreadPool(1)
static ScheduledExecutorServicenewSingleThreadScheduledExecutor()
創建一個單線程的線程池,它可安排在給定延遲後運行或者定期地執行。
ExecutorService 常用方法:
void execute(Runnable command) 執行給定的命令,此方法從父接口Executor中繼承而來。
void shutdown()
執行以前提交的任務,但不接受新任務,任務執行完成後池中所有的線程都將死亡。
List<Runnable> shutdownNow() 試圖停止所有正在執行的活動任務,暫停處理
正在等待的任務,並返回等待執行的任務列表。
<T> Future<T> submit(Callable<T> task)
提交一個返回值的任務用於執行,返回一個表示任務的結果的Future。
Future<?> submit(Runnable task) 提交一個 Runnable 任務用於執行,並返回一個
表示該任務的 Future。Future無意義 。
Future類中常用方法:
V get() 等待計算完成,然後獲取其結果。
V get(long timeout, TimeUnit unit)
最多等待爲使計算完成所給定的時間之後,獲取其結果(如果結果可用)。
boolean isCancelled() 如果在任務正常完成前將其取消,則返回 true。
boolean isDone() 如果任務已完成,則返回 true。
ScheduledExecutorService類繼承了ExecutorService接口,常用方法有:
<V> ScheduledFuture<V> schedule(Callable<V> callable, longdelay, TimeUnit unit)
創建並執行在給定延遲後啓用的ScheduledFuture。
ScheduledFuture<?> schedule(Runnable command,long delay, TimeUnit unit)
創建並執行在給定延遲後啓用的一次性操作。
ScheduledFuture<?> scheduleAtFixedRate(Runnablecommand, long initialDelay, long period, TimeUnit unit)
創建並執行一個在給定初始延遲後首次啓用的定期操作,後續操作具有給定的週期;也就是將在 initialDelay 後開始執行,然後在 initialDelay+period 後執行,接着在 initialDelay + 2 * period 後執行,依此類推。
ScheduledFuture<?> scheduleWithFixedDelay(Runnablecommand, long initialDelay, long delay, TimeUnit unit)
創建並執行一個在給定初始延遲後首次啓用的定期操作,隨後,在每一次執行終止和下一次執行開始之間都存在給定的延遲。
示例:
public class TreadPoolTest {
public static void main(String[] args) {
//ExecutorServicepool=Executors.newFixedThreadPool(3);
//ExecutorServicepool=Executors.newCachedThreadPool();
ExecutorServicepool=Executors.newSingleThreadExecutor();
for(int i=0;i<10;i++){
final int a=i;
pool.execute(new Runnable() {
public void run() {
for(int j=0;j<5;j++){
try {
Thread.currentThread().sleep(500);
} catch (InterruptedException e) {
e.printStackTrace(); }
System.out.println("thread:"+a+" loop:"+j);}}});}
Future<String>fut=pool.submit(new Callable<String>() {
public String call()throws Exception {
System.out.println("call is running……");
return "hello,java";}});
System.out.println(fut.get());}}
7.CompletionService用於提交一組Callable任務,其take方法返回任務中已完成的一個Callable任務對應的Future對象。
示例:
ExecutorService service= Executors.newFixedThreadPool(3);
CompletionService<Integer>completionService =
new ExecutorCompletionService<Integer>(service);
for (int i = 0; i < 20; i++) {
completionService.submit(new Callable<Integer>(){
public Integer call()throws Exception {
Integer a = 0;
try {
a = new Random().nextInt(10);
System.out.println("product a:" + a);
Thread.sleep((long) (a * 100));
} catch (Exception e) {
}
return a;
}
});
}
for (int i = 0; i < 20; i++) {
Future<Integer> f = completionService.take();
System.out.println("get a:" + f.get());
}
以上代碼基本上遵循返回一個數,得到一個數的趨勢。
8.讀寫鎖:
示例:
public class LockTest {
static Source source=new Source();
public static void main(String []a){
for(int i=0;i<4;i++){
new Thread(new Runnable() {
public void run() {
source.setA();}}).start();
new Thread(new Runnable() {
public void run() {
source.getA();}}).start();}}}
class Source{
int a=0;
ReadWriteLock rwl=new ReentrantReadWriteLock();
void setA(){
rwl.writeLock().lock();
System.out.println(Thread.currentThread().getName()+
" 準備產生a……");
try {
Thread.currentThread().sleep(1000);
} catch (Exception e) {
e.printStackTrace();}
a=new Random().nextInt();
System.out.println(a);
System.out.println("已經產生a");
rwl.writeLock().unlock();}
void getA(){
rwl.readLock().lock();
System.out.println(Thread.currentThread().getName()+
" 準備得到a……");
try {
Thread.currentThread().sleep(1000);
} catch (Exception e) {
e.printStackTrace();}
System.out.println(a);
System.out.println("已經得到a");
rwl.readLock().unlock();}}
通常在釋放鎖時,代碼放在finally中,避免拋出異常時,鎖爲釋放資源。
讀寫鎖應用之緩存系統:
public class CacheDemo {
privateMap<String, Object> cache = new HashMap<String, Object>();
public staticvoid main(String[] args) { }
privateReadWriteLock rwl = new ReentrantReadWriteLock();
public Object getData(String key){
rwl.readLock().lock();
Object value = null;
try{
value= cache.get(key);
if(value== null){
rwl.readLock().unlock();
rwl.writeLock().lock();
try{
if(value==null){
value = "aaaa";//實際是去queryDB();
}
}finally{
rwl.writeLock().unlock();
}
rwl.readLock().lock();
}
}finally{
rwl.readLock().unlock();
}
return value;
}
}
---------------------- android培訓、java培訓、期待與您交流! ----------------------