new Thread(new Runnable() {
      @Override
      public void run() {
         //耗时代码
      }
}).start();这种方式的线程随处可见,但是这种方式的写法是存在一定问题的,我们知道,在操作系统中,线程是操作系统调度的最小单元,同时线程又不能无限制的产生,并且线程的创建和销毁都会有资源的开销,同时当线程频繁的创建或者销毁的时候,还会让GC频繁的运行,造成程序的卡顿,例如当我们需要网络请求的时候,一定是讲网络请求的代码放到子线程中去运行的,同时如果是ListView中图片的画,采用传统的new
 Thread的形式,会在ListView滑动的时候,一下开数十个子线程,程序就会卡顿起来;或者当我们进行下载的时候,通常会指定下载的优先级,优先级高的优先下载,优先级低的会暂停排队,这种需求传统的Thread也是做不到的。那么这就需要用到线程池了。public ThreadPoolExecutor(int corePoolSize,
                              int maximumPoolSize,
                              long keepAliveTime,
                              TimeUnit unit,
                              BlockingQueue<Runnable> workQueue,
                              ThreadFactory threadFactory,
                              RejectedExecutionHandler handler)我们来看看这几个参数的意义:(以下的所说的任务可以理解为实现Runnable接口的对象)threadPoolExecutor.allowCoreThreadTimeOut(true);
值得注意的是,并不是说只有核心线程才能去执行任务,而是核心线程是最稳定的线程,在默认状态下,它们不会销毁,这样在新的任务需要执行的时候,就会很节省时间,所以核心线程数只需要保证大于0就可以了。
Thread newThread(Runnable r);
public void rejectedExecution(Runnable r, ThreadPoolExecutor e) {
           if (!e.isShutdown()) {
               r.run();
           }
       }使用执行线程池的线程本身来运行该任务,此策略提供简单的反馈控制机制,能减缓新任务的提交速度。public void rejectedExecution(Runnable r, ThreadPoolExecutor e) {
           throw new RejectedExecutionException();
       }这种策略直接抛出异常,丢弃任务public void rejectedExecution(Runnable r, ThreadPoolExecutor e) {
       }这种策略也是丢弃任务,不同的是,它并不会抛出异常public void rejectedExecution(Runnable r, ThreadPoolExecutor e) {
           if (!e.isShutdown()) {
               e.getQueue().poll();
               e.execute(r);
           }
       }    public static ExecutorService newFixedThreadPool(int nThreads) {
        return new ThreadPoolExecutor(nThreads, nThreads,
                                      0L, TimeUnit.MILLISECONDS,
                                      new LinkedBlockingQueue<Runnable>());
    }      ExecutorService fixedThreadPool = Executors.newFixedThreadPool(3);
        for (int i = 1; i <= 10; i++) {
            final int index = i;
            fixedThreadPool.execute(new Runnable() {
                @Override
                public void run() {
                    String threadName = Thread.currentThread().getName();
                    System.out.println("线程:" + threadName + ",任务:" + index);
                    try {
                        //模拟耗时
                        Thread.sleep(2000);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            });
        }我们创建了一个最大线程和核心线程都是3的一个线程池,然后向其中循环添加10个任务,每一个人只打印当前线程的名字,来看一下效果    public static ExecutorService newCachedThreadPool() {
        return new ThreadPoolExecutor(0, Integer.MAX_VALUE,
                                      60L, TimeUnit.SECONDS,
                                      new SynchronousQueue<Runnable>());
    }通过它的实例方法可以看出它的核心线程数是0也就是说该线程池并没有核心线程,而它的最大线程数是int类型的的上限,那么我们可以理解为该线程池的最大线程数是没有上限的,也就是说可以无限的创建线程。那么当新任务向线程池中提交的时候,如果有空闲线程,就会把任务放到空闲线程中去,如果没有空闲线程,就会开启一个新的线程来执行此任务,而它的队列SynchronousQueue是一个特殊的队列,在多数情况下,我们可以把它简单的理解为一个无法插入的队列,我们会在之后详细说明的。        ExecutorService cachedThreadPool = Executors.newCachedThreadPool();
        for (int i = 1; i <= 10; i++) {
            final int index = i;
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            cachedThreadPool.execute(new Runnable() {
                @Override
                public void run() {
                    String threadName = Thread.currentThread().getName();
                    System.out.println("线程:" + threadName + ",任务:" + index);
                    try {
                        long time = index * 500;
                        Thread.sleep(time);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            });
        }我们这次是在每一次添加的时候都会停止1s的时间,来看看CachedThreadPool的运行情况,并且,每一个任务所执行的时间也不一样,效果如下public static ScheduledExecutorService newScheduledThreadPool(int corePoolSize) {
        return new ScheduledThreadPoolExecutor(corePoolSize);
    }public ScheduledThreadPoolExecutor(int corePoolSize) {
        super(corePoolSize, Integer.MAX_VALUE,
              DEFAULT_KEEPALIVE_MILLIS, MILLISECONDS,
              new DelayedWorkQueue());
    }可以看出它的核心线程数是固定的,而最大线程数也是int类型的上限,理解为没有限制,它与之前的线程池相区别的就是它的任务队列,DelayedWorkQueue能让任务周期性的执行,也就是说该线程池可以周期性的执行任务。        ScheduledExecutorService scheduledThreadPool = Executors.newScheduledThreadPool(3);
        //延迟2秒后执行该任务
        System.out.println("任务开始");
        scheduledThreadPool.schedule(new Runnable() {
            @Override
            public void run() {
                String threadName = Thread.currentThread().getName();
                System.out.println("任务:" + threadName );
            }
        }, 3, TimeUnit.SECONDS);我们首先模拟延迟执行任务的代码,在我们提交任务之前先打印一次任务开始,在提交任务的时候,去设置延迟时间为3s,运行一下看看效果ScheduledExecutorService scheduledThreadPool = Executors.newScheduledThreadPool(3);
        //延迟2秒后执行该任务
        System.out.println("任务开始");
        //延迟4秒后,每隔1秒执行一次该任务
        scheduledThreadPool.scheduleAtFixedRate(new Runnable() {
            @Override
            public void run() {
                System.out.println("执行任务");
            }
        }, 4, 1, TimeUnit.SECONDS);我们设置了在提交任务时,需要延迟4s才会第一次执行,同时在任务执行完毕后每隔1s又会重复的执行一次该任务,看一下效果public static ExecutorService newSingleThreadExecutor() {
        return new FinalizableDelegatedExecutorService
            (new ThreadPoolExecutor(1, 1,
                                    0L, TimeUnit.MILLISECONDS,
                                    new LinkedBlockingQueue<Runnable>()));
    }通过代码可以看出,这种线程池,就是FixedThreadPool但是实例化方法的参数是1的嘛。public abstract class PriorityRunnable implements Runnable, Comparable<PriorityRunnable> {
    private int priority;
    public PriorityRunnable(int priority) {
        if (priority < 0) {
            throw new IllegalArgumentException();
        }
        this.priority = priority;
    }
    @Override
    public int compareTo(PriorityRunnable another) {
        return another.getPriority() - priority;
    }
    public int getPriority() {
        return priority;
    }
}
我们的抽象类最基本的需要实现Runnable接口才能被提交到线程池中,同时我们需要再实现Compareable接口,来告诉队列到底谁大谁小,这里我们自己写了一个int类型的变量代表每一个任务的优先级,然后复写compareTo方法来写我们的比较条件,这里要注意的是,当我们自己去写的时候,不一定非要指定一个int类型的变量,也可以是其他的例如String等的,只要实现了Comparable接口就可以了。接下来我们就可以使用这个任务了,代码如下ExecutorService priorityThreadPool = new ThreadPoolExecutor(3, 3, 0L, TimeUnit.MILLISECONDS, new PriorityBlockingQueue<Runnable>());
        for (int i = 1; i <= 10; i++) {
            final int priority = i;
            priorityThreadPool.execute(new PriorityRunnable(priority) {
                @Override
                public void run() {
                    String threadName = Thread.currentThread().getName();
                    System.out.println("线程:" + threadName + ",正在执行优先级为:" + priority + "的任务");
                    try {
                        Thread.sleep(2000);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            });
        }我们创建了一个核心线程为3的使用优先级队列的线程池,向线程池中添加10个优先级不同的任务,来看看效果public class MyThreadPool extends ThreadPoolExecutor {
    public MyThreadPool(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue<Runnable> workQueue) {
        super(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue);
    }
    @Override
    protected void beforeExecute(Thread t, Runnable r) {
        super.beforeExecute(t, r);
        //在执行任务之前
    }
    @Override
    protected void afterExecute(Runnable r, Throwable t) {
        super.afterExecute(r, t);
        //在执行任务之后
    }
    @Override
    protected void terminated() {
        super.terminated();
        //线程池关闭
    }
}类似这样,就可以在线程池执行任务之前和之后,都很方便的加上我们的功能 //只有一个位置的信号量,相当于停车场只有一个位置
        final Semaphore semp = new Semaphore(2);
        for(int i = 0;i<4;i++){
            new Thread(new Runnable() {
                @Override
                public void run() {
                    String threadName = Thread.currentThread().getName();
                    try {
                        //申请信号量
                        semp.acquire();
                        System.out.println(threadName+"申请到了信号量");
                        Thread.sleep(2000);
                        //释放信号量
                        semp.release();
                        System.out.println(threadName+"释放了了信号量");
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }).start();
        }首先我们定义了一个只有2个位置的信号量,然后循环开启了4个线程,而这4个线程可以理解为几乎是在同一时间开启的,当线程开始的时候会尝试申请信号量,如果申请成功就开始模拟一个耗时操作,在操作完成后,再释放一次信号量,我们来看一看这几个线程的运行情况<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:paddingBottom="@dimen/activity_vertical_margin"
    android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
    android:orientation="vertical"
    tools:context="com.lanou.chenfengyao.myapplication.MainActivity">
<LinearLayout
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:orientation="horizontal">
    <Button
        android:id="@+id/btn_FIFO"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="FIFO"/>
    <Button
        android:id="@+id/btn_LIFO"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="LIFO"/>
</LinearLayout>
    <TextView
        android:id="@+id/main_text"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Hello World!" />
</LinearLayout>
这个不用多说,就是2个Button来控制线程池的,一个TextView用来显示当前的线程的public class MainActivity extends AppCompatActivity implements View.OnClickListener {
    private Button FIFOBtn, LIFOBtn;
    private TextView mainTv;
    private MyThreadPool myThreadPool;
    private Handler handler;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        FIFOBtn = (Button) findViewById(R.id.btn_FIFO);
        LIFOBtn = (Button) findViewById(R.id.btn_LIFO);
        mainTv = (TextView) findViewById(R.id.main_text);
        FIFOBtn.setOnClickListener(this);
        LIFOBtn.setOnClickListener(this);
        handler = new Handler(new Handler.Callback() {
            @Override
            public boolean handleMessage(Message msg) {
                //设置给TextView;
                mainTv.setText("任务:"+msg.what);
                return false;
            }
        });
        myThreadPool = new MyThreadPool(1);
        for (int i = 0; i < 100; i++) {
            final int index = i;
            myThreadPool.execute(new Runnable() {
                @Override
                public void run() {
                    handler.sendEmptyMessage(index);
                    try {
                        Thread.sleep(1000);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            });
        }
    }
    @Override
    public void onClick(View v) {
        switch (v.getId()) {
            case R.id.btn_FIFO:
                myThreadPool.setWay(MyThreadPool.OutWay.FIFO);
                break;
            case R.id.btn_LIFO:
                myThreadPool.setWay(MyThreadPool.OutWay.LIFO);
                break;
        }
    }
}我直接在onCreate方法里创建了我自定义的一个线程池,然后向里面添加了100个任务,而这个线程池的核心线程和最大线程我都设置成了1个,每一个任务也就是把自己任务号通过handler发送给主线程,然后显示到TextView上,在按钮的监听里,调用自定义线程池的setWay方法,把FIFO还是LIFO的信息设置上,那么关键的代码就在我们自定义的线程池里了,我们来看一下:package com.lanou.chenfengyao.myapplication;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.Semaphore;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
/**
 * Created by ChenFengYao on 16/5/17.
 */
public class MyThreadPool extends ThreadPoolExecutor {
    private volatile Semaphore semaphore;
    private List<Runnable> runnableList;
    private LoopThread loopThread;
    private boolean flag;
    //两种策略,先进先出和先进后出
    enum OutWay {
        FIFO, LIFO
    }
    private OutWay outWay;
    public MyThreadPool(int corePoolSize) {
        super(corePoolSize, corePoolSize, 0l, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<Runnable>());
        semaphore = new Semaphore(corePoolSize);
        runnableList = new LinkedList<>();
        flag = true;
        outWay = OutWay.FIFO;//默认是先进先出
        loopThread = new LoopThread();
        loopThread.start();
    }
    //提交任务的方法
    @Override
    public synchronized void execute(Runnable command) {
        //所有来的任务是提交到我们自己的任务队列中
        runnableList.add(command);
        if (runnableList.size() < 2) {
            //如果这是队列中的第一个任务,那么就去唤醒轮询线程
            synchronized (loopThread) {
                loopThread.notify();
            }
        }
    }
    //设置是FIFO/LIFO
    public void setWay(OutWay outWay) {
        this.outWay = outWay;
    }
    @Override
    protected void afterExecute(Runnable r, Throwable t) {
        super.afterExecute(r, t);
        //任务完成释放信号量
        semaphore.release();
    }
    @Override
    protected void terminated() {
        super.terminated();
        flag = false;//轮询线程关闭
    }
    class LoopThread extends Thread {
        @Override
        public void run() {
            super.run();
            while (flag) {
                if (runnableList.size() == 0) {
                    try {
                        //如果没有任务,轮询线程就等待
                        synchronized (this) {
                            wait();
                        }
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                } else {
                    try {
                        //请求信号量
                        semaphore.acquire();
                        int index = runnableList.size();
                        switch (outWay) {
                            case FIFO:
                                //先进先出
                                index = 0;
                                break;
                            case LIFO:
                                //先进后出
                                index = runnableList.size() - 1;
                                break;
                        }
                        //调用父类的添加方法,将任务添加到线程池中
                        MyThreadPool.super.execute(runnableList.get(index));
                        runnableList.remove(index);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }
        }
    }
}
可以看到,这个自定义的线程池的核心线程和最大线程都是一样的,通过构造方法传进来的,这里是1,同时,我们将我们信号量的数值也设置为核心线程数,并且我们在内部有一个List用来存放我们提交的任务,我将线程池父类的execute方法复写了,这里不再向线程池内提交,而是存放到我们自己的RunnableList里。Runtime.getRuntime().availableProcessors();来获得
原文:http://blog.csdn.net/cfy137000/article/details/51422316