Android线程池(二)

255 阅读2分钟

「这是我参与11月更文挑战的第24天,活动详情查看:2021最后一次更文挑战

三、Android 中常用的几种线程池

1.FixedThreadPool (可重用固定线程数)

public static ExecutorService newFixedThreadPool(int nThreads) {
        return new ThreadPoolExecutor(nThreads, nThreads,
                                      0L, TimeUnit.MILLISECONDS,
                                      new LinkedBlockingQueue<Runnable>());
    }

特点:参数为核心线程数,只有核心线程,无非核心线程,并且阻塞队列无界
创建

//创建fixed线程池

  final ExecutorService fixedThreadPool = Executors.newFixedThreadPool(5);

使用

 /**
     * fixed线程池
     */
        mFixedPoolThread.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                for(int i = 0;i<30;i++){
                    final int finali = i;
                    Runnable runnable = new Runnable() {
                        @Override
                        public void run() {
                            try {
                                Thread.sleep(2000);
                                Log.d("Thread", "run: "+finali);
                                Log.d("当前线程:",Thread.currentThread().getName());
                            } catch (InterruptedException e) {
                                e.printStackTrace();
                            }
                        }
                    };
                    fixedThreadPool.execute(runnable);

                }
            }
        });

结果为每2s打印5次任务,跟上面的基础线程池类似
2.CachedThreadPool

public static ExecutorService newCachedThreadPool() {
        return new ThreadPoolExecutor(0, Integer.MAX_VALUE,
                                      60L, TimeUnit.SECONDS,
                                      new SynchronousQueue<Runnable>());
    }

CachedThreadPool中是没有核心线程的,但是它的最大线程数却为Integer.MAX_VALUE,另外,CachedThreadPool是有线程超时机制的,它的超时时间为60秒。

由于最大线程数为无限大,所以每当添加一个新任务进来的时候,如果线程池中有空闲的线程,则由该空闲的线程执行新任务;如果没有空闲线程,则创建新线程来执行任务。

根据CachedThreadPool的特点,在有大量耗时短的任务请求时,可使用CachedThreadPool,因为当CachedThreadPool中没有新任务的时候,它里边所有的线程都会因为60秒超时而被终止
创建

//创建Cached线程池

 final ExecutorService cachedThreadPool = Executors.newCachedThreadPool();

使用

 /**
    * cached线程池
    */
        mCachedPoolThread.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                for(int i = 0;i<30;i++){
                    final int finali = i;
                    Runnable runnable = new Runnable() {
                        @Override
                        public void run() {
                            try {
                                Thread.sleep(2000);
                                Log.d("Thread", "run: "+finali);
                            } catch (InterruptedException e) {
                                e.printStackTrace();
                            }
                        }
                    };
                    cachedThreadPool.execute(runnable);

                }
            }
        });

结果:过2s后直接打印30个任务
3.SingleThreadPool(单个核线的fixed)

public ScheduledThreadPoolExecutor(int corePoolSize) {  
    super(corePoolSize, Integer.MAX_VALUE,  
          DEFAULT_KEEPALIVE_MILLIS, MILLISECONDS,  
          new DelayedWorkQueue());  
} 

它的核心线程数量是固定的,但是非核心线程无穷大。当非核心线程闲置时,则会被立即回收。
ScheduledThreadPool也是四个当中唯一一个具有定时定期执行任务功能的线程池。它适合执行一些周期性任务或者延时任务。
创建

//创建Single线程池
 final ExecutorService singleThreadExecutor = Executors.newSingleThreadExecutor();

使用

/**
    * single线程池
    */
        mSinglePoolExecute.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                for(int i = 0;i<30;i++){
                    final int finali = i;x
                    Runnable runnable = new Runnable() {
                        @Override
                        public void run() {
                            try {
                                Thread.sleep(2000);
                                Log.d("Thread", "run: "+finali);
                            } catch (InterruptedException e) {
                                e.printStackTrace();
                            }
                        }
                    };
                    singleThreadExecutor.execute(runnable);

                }
            }
        });

结果:每2s打印一个任务,由于只有一个核心线程,当被占用时,其他的任务需要进入队列等待。

四、终止线程池中的某个线程

一般线程执行完run方法之后,线程就正常结束了,因此有如下几种方式来实现:
1.利用 Future 和 Callable
步骤:
实现 Callable 接口
调用 pool.submit() 方法,返回 Future 对象
用 Future 对象来获取线程的状态。

private void cancelAThread() {
        ExecutorService pool = Executors.newFixedThreadPool(2);
          
          Callable<String> callable = new Callable<String>() {
              
            @Override
            public String call() throws Exception {
                System.out.println("test");
                return "true";
            }
        };
          
        Future<String> f = pool.submit(callable);
          
        System.out.println(f.isCancelled());
        System.out.println(f.isDone());
        f.cancel(true);
  
    }

2.利用 volatile 关键字,设置退出flag, 用于终止线程

public class ThreadSafe extends Thread {
    public volatile boolean isCancel = false; 
        public void run() { 
        while (!isCancel){
           //TODO method(); 
        }
    } 
}

3.interrupt()方法终止线程,并捕获异常

public class ThreadSafe extends Thread {
  
   @Override
    public void run() { 
        while (!isInterrupted()){ //非阻塞过程中通过判断中断标志来退出
            try{
              //TODO method(); 
              //阻塞过程捕获中断异常来退出
            }catch(InterruptedException e){
                e.printStackTrace();
                break;//捕获到异常之后,执行break跳出循环。
            }
        }
    } 
}