java使用Executor(執行器)管理線程


一.一個實現了Runnable接口的類

class MyThread implements Runnable{
    private static int num = 0;
    @Override
    public void run() {
        while(true){
            synchronized(MyThread.class){
                ++num;
                try{
                    Thread.sleep(500);
                } catch(Exception e){
                    System.out.println(e.toString());
                }
                System.out.println(Thread.currentThread().getName() + " " + num);
            }
        }
    }
}

1. newCachedThreadPool()方法

  CacheThreadPool會為每一個任務創建一個線程。非常常見的情況是,單個的Executor被用來創建和管理系統中的任務。shutdown()方法可以防止新的任務被提交給這個Executor。如果在shutdown()方法之后提交新任務,則會拋出java.util.concurrent.RejectedExecutionException異常。

public class Main{
    public static void main(String[] args){
          ExecutorService exes = Executors.newCachedThreadPool();
          for(int i=0; i<5; ++i)
              exes.execute(new MyThread());
          exes.shutdown();          
    }
}

2.FixedThreadPool()方法

  FixedThreadPool使用了優先的線程集來執行所提交的任務。有了它,你就可以一次性預先執行代價高的線程分配。也就是說如果設置的最大線程數量是x,而提交的線程數y,那么(y-x)對應的這些線程要等到前x個線程執行完畢才會執行。

  下面的例子中,線程6一直不會有機會執行。因為run()方法中是 while(true), 可以將while(true)去掉,前5個線程執行完畢后,才會執行第6個線程。

public class Main{
    public static void main(String[] args){
          ExecutorService exes = Executors.newFixedThreadPool(5);
          for(int i=0; i<6; ++i)
                  exes.execute(new MyThread());
          exes.shutdown();          
    }
}

3.newSingleThreadExecutor()方法

public class Main{
    public static void main(String[] args){        
          ExecutorService exes = Executors.newSingleThreadExecutor();
          for(int i=0; i<5; ++i)
              exes.execute(new MyThread());
          exes.shutdown();    
}

  SingleThreadExecutor就像是線程數量為1的FixedThreadPool。這對於你希望在另一個線程中連續運行的事物(長期存活的任務)來說,都是很有用的。如果想SingleThreadExecutor提交了多個任務,那么這些任務將排隊,每個任務都會在下一個任務開始之前結束,所有的任務將使用相同的線程。

 

二.一個實現了Callable<E>接口的類(從任務中產生返回值)

class MyThread implements Callable<String>{
    private static int num = 0;
    @Override
    public String call() throws Exception {
        for(int i=0; i<5; ++i){
            synchronized(MyThread.class){
                ++num;
                Thread.sleep(200);
                System.out.println(Thread.currentThread().getName() + " " + num);
            }
        }
        return Thread.currentThread().getName() + " success!";
    }
}

1.ExecutorService.submit()方法

public class Main{
    public static void main(String[] args){
         ExecutorService exes = Executors.newCachedThreadPool();
         ArrayList<Future<String>> rets = new ArrayList<Future<String>>();
         for(int i=0; i<5; ++i)
             rets.add(exes.submit(new MyThread()));
         for(Future<String> fs : rets){
            try {
                System.out.println(fs.get());
            } catch (InterruptedException e) {
                e.printStackTrace();
            } catch (ExecutionException e) {
                e.printStackTrace();
            }
         }
    }
}

  submit()會產生Future對象,它用Callable返回結果的特定類型進行了參數化。可以調用Future的isDone()方法來查詢Future是否已經完成。調用Future的get()方法來獲取最終線程的執行結果。另外,Future的get()方法是一個阻塞方法,直到結果准備就緒

 三.線程的優先級

class MyThread implements Runnable{
    private int priority;
    public MyThread(){
    }
    
    public MyThread(int priority){
        this.priority = priority;
    }
    
    private static int num = 0;
    private volatile double d;
    @Override
    public void run() {
        Thread.currentThread().setPriority(priority); while(true){
            for(int i=0; i<100000; ++i){
                d += (Math.PI+Math.E)/(double)i;
                if(i%1000 == 0)
                    Thread.yield();
            }
            synchronized(MyThread.class){
                ++num;
                try{
                    Thread.sleep(500);
                } catch(Exception e){
                    System.out.println(e.toString());
                }
                System.out.println(Thread.currentThread().getName() + " " + num);
            }
        }
    }
}

public class Main{
    public static void main(String[] args){
         ExecutorService exes = Executors.newCachedThreadPool();
         for(int i=0; i<5; ++i)
             exes.execute(new MyThread(Thread.MIN_PRIORITY));
         exes.execute(new MyThread(Thread.MAX_PRIORITY));
         exes.shutdown();
    }
}

  volatile變量保證編譯器對循環不進行任何的優化,如果不加入這些運算的話,就不會看到設置線程優先級的效果。數學運算是可以中斷的,向控制台打印不能被中斷。這里預案算時間足夠的長,因此線程調度機制才來的及介入,交換任務並關注優先級,是的最高優先級被優先選擇。

四.后台線程

class SimpleDaemons implements Runnable{
    @Override
    public void run() {
        while(true){
            try{
                TimeUnit.MILLISECONDS.sleep(200);
                System.out.println(Thread.currentThread().getName());
            } catch(InterruptedException e){
                System.out.println(Thread.currentThread().getName() + " : InterruptException!");
                e.printStackTrace();
            }
        }
    }
}

public class Main{
    public static void main(String[] args) throws InterruptedException{
         for(int i=0; i<10; ++i){
             Thread daemon = new Thread(new SimpleDaemons());
             daemon.setDaemon(true);
             daemon.start();
         }
         System.out.println("All daemons started");
         TimeUnit.MILLISECONDS.sleep(1000);
    }
}

  所謂后台線程,是指程序運行的時候在后台提供一種通用的服務的線程,並且這種線程並不屬於程序中不可或缺的部分。因此,當所有的非后台線程結束時,程序也就終止了,同時會殺死進程中的所有的后台線程。反過來說,只要任何非后台線程還在運行,程序就不會終止。

  通過定制自己的ThreadFactory, 可以定制有Executor創建的線程的屬性(后台,優先級,名稱)

class DaemonThreadFactory implements ThreadFactory{
    @Override
    public Thread newThread(Runnable r) {
        Thread t = new Thread(r);
        t.setDaemon(true);
        return t;
    }
}
class DaemonFromFactory implements Runnable{
    @Override
    public void run() {
        try{
            TimeUnit.MILLISECONDS.sleep(100);
            System.out.println(Thread.currentThread().getName());
        } catch (InterruptedException e){
            e.printStackTrace();
        }
    }
}

public class Main{
    public static void main(String[] args) throws InterruptedException{
         ExecutorService exes = Executors.newCachedThreadPool(new DaemonThreadFactory());
         for(int i=0; i<5; ++i)
                 exes.execute(new DaemonFromFactory());
         System.out.println("All Daemos Started!");
         TimeUnit.MILLISECONDS.sleep(1000);
    }
}

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM