程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> JAVA編程 >> 關於JAVA >> 0041 Java學習筆記-多線程-線程池、ForkJoinPool、ThreadLocal

0041 Java學習筆記-多線程-線程池、ForkJoinPool、ThreadLocal

編輯:關於JAVA

0041 Java學習筆記-多線程-線程池、ForkJoinPool、ThreadLocal。本站提示廣大學習愛好者:(0041 Java學習筆記-多線程-線程池、ForkJoinPool、ThreadLocal)文章只能為提供參考,不一定能成為您想要的結果。以下是0041 Java學習筆記-多線程-線程池、ForkJoinPool、ThreadLocal正文


什麼是線程池

  • 創立線程,由於觸及到跟操作零碎交互,比擬消耗資源。假如要創立少量的線程,而每個線程的生活期又很短,這時分就應該運用線程池了,好像數據庫的銜接池一樣,事後開啟一定數量的線程,有義務了就將義務傳遞出來,義務執行終了不終止線程,等候下一個義務

線程池的品種

  • ExecutorService:
    • 這是個接口,代表盡快執行的線程池,只需有閒暇進程,就立刻執行
    • Future<?> submit(Runnable task)
      • 將Runnable對象提交給線程池,線程池有閒暇線程時執行義務,前往的Future對象,由於run()沒有前往值,因而實踐是null,但可以調用isDone()和isCancelled()辦法
    • <T> Future <T> submit(Runnable task,T result)
      • result是線程執行完畢後的前往值
    • <T> Future <T> submit(Callable<T> task)
      • Future代表Callable的call()辦法的前往值
    • void shutdown()
      • 不再接納新義務,已接納的義務執行完成,然後封閉線程池
    • List<Runnable> shutdownNow()
      • 中止一切線程義務,並前往等候處置的義務列表
    • boolean isShutdown()
    • boolean isTerminated()
      • shutdown()之後,一切義務都執行終了,則前往true
  • ScheduledExecutorService
    • 這也是個接口,代表在指定延遲或許周期性的執行義務的線程池
    • ScheduledFuture<V> schedule(Callable<V> callable,long delay,TimeUnit unit)
      • Callable義務在delay後執行
    • ScheduledFuture<?> schedule(Runnable command, long delay, TimeUnit unit)
      • Runnable義務在delay後執行
    • ScheduledFuture<?> scheduleAtFixedTate(Runnable command, long initialDelay, long period, TimeUnit unit)
      • 在delay延遲後開端執行,之後周期性(period)執行
      • 這裡的周期是從上一個義務的開端時間開端計算
      • 比方:第一次執行義務在1秒處,執行了3秒,第4秒完畢,假如設置的period是5秒,那就在第6秒第二次執行該義務
      • TimeUnit是個枚舉類:可以是天、小時、分鐘、秒、毫秒、毫微秒
    • ScheduledFuture<?> scheduleWithFixedDelay(Runnable command, long initialDelay, long delay, TimeUnit unit)
      • initialDelay後開端執行,執行終了後,距離delay後再次執行
      • 執行中遇到異常,會終止執行,否則會不斷執行,應設立條件終止義務
      • 跟上一個辦法不同的是,這個辦法,第二個周期執行的起算點是第一個周期完畢時間

創立線程池

  • 經過Executors的靜態工廠辦法創立線程池
  • 創立ExecutorService線程池
    • newCachedThreadPool()
      • 具有緩存功用的線程池,零碎依據需求創立線程,緩存與線程池中
    • newFixedThreadPool(int nThreads)
      • 可重用的、具有固定線程數的線程池
    • newSingleThreadExecutor()
      • 單線程的線程池
    • newWorkStealingPool(int parallelism)
      • 創立以訛持有足夠線程的線程池來支持給定的並行級別,並且運用多個隊列來增加競爭
    • newWorkStealingPool()
      • 這個辦法是上個辦法的簡化版,將cpu個數傳給上一個辦法就是上面這個辦法
  • 創立ScheduledExecutorService線程池
    • newScheduledThreadPool(int corePoolSize)
      • corePoolSize是線程數目
    • newSingleThreadScheduledExecutor()
      • 只要一個線程

示例一:

package testpack;

import java.util.Date;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;

public class Test2  { 
    public static void main(String[] args) throws InterruptedException{ 
        Runnable task=()->{                        //創立一個線程義務
            for (int i=0;i<1;i++) {
                System.out.println(new Date());
                try{
                    Thread.sleep(3000);
                }catch(InterruptedException ex){
                    ex.printStackTrace();
                }
                System.out.println(new Date());
            }
        };
        ScheduledExecutorService ses=Executors.newScheduledThreadPool(1);  //創立一個單線程延遲處置處置線程池,
        ses.scheduleAtFixedRate(task,1,5,TimeUnit.SECONDS);     //標志㈠。延遲1秒開端處置,從開端處置的時間點開端算,5秒後執行第二個周期
    }
}

輸入:

Fri Dec 09 16:22:07 CST 2016 //07秒開端處置
Fri Dec 09 16:22:10 CST 2016 //run中暫停3秒
Fri Dec 09 16:22:12 CST 2016 //07+5秒開端第二個周期
Fri Dec 09 16:22:15 CST 2016 //run中暫停3秒
Fri Dec 09 16:22:17 CST 2016 //07+5+5開端第三個周期

示例二:將下面標志㈠的辦法改為:scheduleWithFixedDelay,輸入如下:

Fri Dec 09 16:28:35 CST 2016 //35秒開端處置
Fri Dec 09 16:28:38 CST 2016 //run中暫停3秒
Fri Dec 09 16:28:43 CST 2016 //38+5秒開端第二個周期
Fri Dec 09 16:28:46 CST 2016 //run中暫停3秒
Fri Dec 09 16:28:51 CST 2016 //46+5秒開端第三個周期

ForkJoinPool

  • ForkJoinPool與多CPU、多核CPU計算有關
  • 是ExecutorService的完成類,也是一種線程池
  • 配合ForkJoinTask完成對一個大義務停止遞歸拆解成多個小義務並行計算
  • 結構器與辦法:
    • ForkJoinPool(int parallelism)
      • 創立一個包括指定個數並行線程的線程池
    • ForkJoinPool()
      • 創立一個Runtime.availableProcessors()前往值個數的並行線程的線程池
    • static ForkJoinPool commenPool()
      • 前往一個通用線程池,其運轉形態不受shutdown()和shutdownNow()的影響,除非調用System.exit()加入虛擬機
    • static int getCommenPoolparallelism()
      • 前往通用池的並行級別
    • submit(ForkJoinTask task)
      • 執行指定義務
    • invoke(ForkJoinTask task)
  • ForkJoinTask
    • 這是個籠統類,有RecursiveAction()和RecursiveTask()兩個籠統子類,前者無前往值,後者有前往值
    • 創立這兩類義務時,要承繼這兩個類,然後重寫compute()辦法
  • 進一步參考:
    • 並發編程網
    • 《Java並發編程的藝術》第6.4節
    • 《Java 7 並發編程實戰手冊》第5章
  • 示例:
package testpack;

import java.util.concurrent.ForkJoinPool;
import java.util.concurrent.RecursiveAction;
import java.util.concurrent.TimeUnit;

public class Test2  { 
    public static void main(String[] args) throws InterruptedException{ 
        ForkJoinPool pool=new ForkJoinPool();
        pool.submit(new Task(0,327));
        pool.awaitTermination(2,TimeUnit.SECONDS);
        pool.shutdown();
    }
}

class Task extends RecursiveAction{
    private static final int THRESHOLD=50;
    private int start;
    private int end;
    public Task(int start,int end){
        this.start=start;
        this.end=end;
    }
    protected void compute(){
        if (end-start<THRESHOLD) {
            for (int i=start;i<end;i++){
                System.out.println(Thread.currentThread().getName()+"輸入: "+i);
            }
        }else{
            int middle = (start+end)/2;
            Task left=new Task(start,middle);
            Task right=new Task(middle,end);
            left.fork();                         
            right.fork();
        }
    }
}

ThreadLocal類

  • ThreadLocal可以把一個多個線程一同操作的變量包裝成一個部分變量,每個線程都擁有一個該變量的正本,各線程對該變量的操作互補影響
  • 只要如下三個辦法:
    • void set(T value)
    • T get();
    • void remove()
  • 各個線程的該部分變量的初始值是null
  • 示例
package testpack;
public class Test1  { 
    public static void main(String[] args){ 
        Account a=new Account("初始名字");
        new MyThread(a).start();
        new MyThread(a).start();
    }
}
class MyThread extends Thread{
    private Account account;
    public MyThread(Account account){
        this.account=account;
    }
    public void run(){
        for (int i=0;i<5;i++) {
            if (i==3){
                account.setName(Thread.currentThread().getName());
            }
            System.out.println("線程稱號:"+getName()+" ,賬戶名:"+account.getName()+" 輸入:"+i);
        }
    }
}
class Account {
    private ThreadLocal<String> name=new ThreadLocal<>();
    public Account(String str){
        this.name.set(str);
        System.out.println("結構時的賬戶名:"+this.name.get());
    }
    public String getName(){
        return name.get();
    }
    public void setName(String str){
        this.name.set(str);
    }
} 

輸入:

結構時的賬戶名:初始名字
線程稱號:Thread-0 ,賬戶名:null 輸入:0
線程稱號:Thread-1 ,賬戶名:null 輸入:0
線程稱號:Thread-0 ,賬戶名:null 輸入:1
線程稱號:Thread-1 ,賬戶名:null 輸入:1
線程稱號:Thread-0 ,賬戶名:null 輸入:2
線程稱號:Thread-1 ,賬戶名:null 輸入:2 //初始值為null
線程稱號:Thread-0 ,賬戶名:Thread-0 輸入:3
線程稱號:Thread-0 ,賬戶名:Thread-0 輸入:4
線程稱號:Thread-1 ,賬戶名:Thread-1 輸入:3
線程稱號:Thread-1 ,賬戶名:Thread-1 輸入:4


  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved