java线程池的使用与实现简单的线程池

来源:互联网 发布:fzltchjw gb1 0 mac 编辑:程序博客网 时间:2024/05/01 23:14

一、线程池是什么?

线程池是一个对于多任务处理或多线程处理的管理方案。我们只需要将任务提交给线程池,就可以完成我们的任务。线程池内部使用了队列对我们的任务进行排队,然后当工作线程空闲时,就去队列取任务进行处理。这就避免了我们自己创建线程。要知道创建线程是个比较重的活,消耗的资源比较大,系统需要为每个线程分配独立的内存空间,需要记录他们的运行状态等等。。。。对于数量多而轻量的任务,为每个任务创建线程就得不偿失了。比如android中的图片加载和服务器的登陆。

二、线程池有什么用?

1.减少创建新线程的资源消耗,对线程进行复用。
2.根据需要有效控制线程数量,避免线程过多,炸了

三、怎么使用线程池?

这里只介绍使用工厂类进行创建线程池,最简单的方法,也是最常用的方法。

0.任务

  • 我们先定义一个测试任务,后面用,任务需要实现Runnable接口。

    public class TestTask implements Runnable{        private int taskid ;        public TestTask(int id) {            this.taskid = id;        }        @Override        public void run() {            System.out.println("正在执行任务->"+taskid);        }    }

1.CachedThreadPool

  • 可缓存线程池,灵活回收空闲线程,线程数无限大。

那么有人问了,既然线程数无限大,那这和我们自己新线程有什么不同呢?

看到了没有,可“缓存”,意思就是它创建的线程不是马上回收的,它会等上一段时间(keepAliveTime),如果有新任务来了,就继续工作,那就重用线程了。

ExecutorService cachedService  = Executors.newCachedThreadPool();        cachedService.execute(new TestTask(0));        cachedService.execute(new TestTask(1));        cachedService.execute(new TestTask(2));

2.SingleThreadExecutor

单线程化线程池,按照指定顺序(FIFO,LIFO)优先级执行。

处理线程数固定为1。

FIFO:先进先出;LIFO:后进先出

这里又有人问了,就一个线程,用处不大啊?

其实我也觉得,哈哈。但是也有它的用途的,由于它是按顺序处理任务的,因此就很好处理任务执行顺序问题,还有就是线程池本身的复用功能了,比如不能在主线程运行的任务,必须创建新线程,这是时候直接使用线程池就行了。

ExecutorService  service  = Executors.newSingleThreadExecutor();//-单一线程池,jdk 1.5        service.execute(new TestTask(0));        service.execute(new TestTask(1));        service.execute(new TestTask(2));       

3.FixedThreadPool

定长线程池,超过最大并发数,则队列等待

可以自定义并发线程数,下面是根据cpu核心数来设定并发线程数,这样可以根据不同的机器启动不同数量的线程,最大化的利用机器性能。

        //获取cpu核心数        int processors = Runtime.getRuntime().availableProcessors();        ExecutorService fixedervice  = Executors.newFixedThreadPool(processors);        fixedervice.execute(new TestTask(0));        fixedervice.execute(new TestTask(1));        fixedervice.execute(new TestTask(2));

4.ScheduledThreadPool

定长线程池,支持定时和周期性任务

可用于定时和周期性的任务。

//实现周期任务ScheduledExecutorService timer = Executors.newScheduledThreadPool(1);// 定时任务        timer.scheduleAtFixedRate(new TestTask(0),         10, //开始时间        10, //周期        TimeUnit.SECONDS/*单位*/);

四、内部原理及实现

如果仅仅限于使用,上面的已经足够日常使用了。但是我们都是喜欢技术的人,希望专研的深层次一点,了解内部是怎么实现的。那么本节将实现一个简单的线程池供各位看看他的真面目。

本实现参考java原生的ThreadPoolExecutor类(也就是上面工厂生成的线程池需要的核心类)实现。有兴趣可以查看ThreadPoolExecutor的源码。看不懂的再看看我这简单的实现~(≧▽≦)/~。

1.我们的需求

java原生的线程池参数是很多的。我们只实现部分。我们就实现一个定长的不需要回收的线程池吧。

2.实现方法

工作线程使用hashset进行存储;任务使用队列进行存储,这里使用LinkedBlockingQueue线程安全的队列;线程池状态使用volatile变量(轻量级的同步变量),并用常量定义了四种状态。需要原子操作时使用事务锁ReentrantLock进行同步。

3.实现原理

先初始化一定的工作线程,并启动,将引用放到hashset中。工作线程是一个死循环,不断尝试去取任务队列的任务,取到就运行任务,取不到等待(Queue.task()),直到用户停止线程池。

4.实现代码

package com.thread;import java.util.HashSet;import java.util.concurrent.LinkedBlockingQueue;import java.util.concurrent.locks.ReentrantLock;/**  * @author  作者 E-mail: yufemgg@gmail.com * @date 创建时间:2016-10-26 上午11:44:40  * @version 1.0  * @Description: */public class ThreadPool {    //线程池的状态    volatile int runState;//volatile变量是一个轻量级的synchronized。    static final int RUNINNG = 0;    static final int SHUTDOWN = 1;    static final int STOP = 2;    static final int TERMINATED = 3;    private int poolSize;    private LinkedBlockingQueue<Runnable> queue = new LinkedBlockingQueue<>();//任务队列,线程安全的    private ReentrantLock lock  = new ReentrantLock();//事务锁,用作同步    private HashSet<WorkThread> work = new HashSet<WorkThread>();//存放工作线程    public ThreadPool(int poolSize) {        this.poolSize = poolSize;        init();        runState = RUNINNG;    }    //提交任务    public boolean execute(Runnable task){        if (task == null)                throw new NullPointerException();        if(runState!=RUNINNG){            return false;//线程池已经终止。         }        return queue.add(task);    }    //初始化工作线程    private void init(){        for (int i = 0; i < poolSize; i++) {            WorkThread w = new WorkThread();            work.add(w);            w.start();        }        log("线程池初始化完成");    }    //修改线程状态为SHUTDOWN,此时不能再添加新任务,但已添加的任务会执行完。    public void shutdown(){        runState = SHUTDOWN;    }    //修改线程状态为SHUTDOWN,此时不能再添加新任务,并尝试停止运行任务,队列中的任务可能不会全部运行完。    public void shutdownNow(){        runState = STOP;    }    //工作线程    class WorkThread extends Thread{        boolean runing = true;        @Override        public void run() {            while (runing) {                Runnable task = null;                task  = getTask();                if(task!=null){                    task.run();                    log(this+"$"+task.toString()+"运行完成");                }else if(task==null&runState>=SHUTDOWN){                    runing = false;                    lock.lock();                    work.remove(this);                    if(work.size()==0){                        runState = TERMINATED;                        log("线程池停止");                    }                    lock.unlock();                }            }        }    }    //到任务队列取一个任务    private Runnable getTask(){        if(runState>SHUTDOWN){            return null;        }else{            try {                return  queue.take();            } catch (InterruptedException e) {                // TODO Auto-generated catch block            }        }        return null;    }    private static void log(String msg){        System.out.println(msg);    }    //test    public static void main(String[] args) {        ThreadPool pool = new ThreadPool(2);        pool.execute(new Runnable() {            @Override            public void run() {                try {                    Thread.sleep(1000);                } catch (InterruptedException e) {                    // TODO Auto-generated catch block                    e.printStackTrace();                }                log("正在运行A");            }        });        pool.execute(new Runnable() {            @Override            public void run() {                try {                    Thread.sleep(1000);                } catch (InterruptedException e) {                    // TODO Auto-generated catch block                    e.printStackTrace();                }                log("正在运行B");            }        });        pool.execute(new Runnable() {            @Override            public void run() {                log("正在运行C");            }        });        pool.shutdown();//      pool.shutdownNow();    }}

附:知识点说明

  1. HashSet 节点不重复的集合。
  2. LinkedBlockingQueue 线程安全的链表式队列。

    • add() 是入队,队列满则抛出异常
    • put() 是入队,队列满则等待
    • offer() 是入队,队列满则返回false

    • poll() 出队,没有元素之间返回null

    • take() 出队,没有元素等待
    • remove() 出队,没有元素抛异常。
  3. ReentrantLock 事务锁,锁内部的代码只有获得锁的时候才能运行,运行完释放锁。保证了内部代码的原子操作。

    • 转载请注明出处:http://blog.csdn.net/u013565368/article/details/52936446

参考文章

【1】http://www.cnblogs.com/dolphin0520/p/3932921.html
【2】http://www.oschina.net/question/565065_86540
【3】http://blog.csdn.net/hsuxu/article/details/8985931
【4】http://blog.csdn.net/z69183787/article/details/46986823

2 0
原创粉丝点击