线程基础----如何编写java线程池(二)

一、场景:

            在了解了线程状态的转换,以及java提供的线程调度的一些方法之后,我尝试写一个线程池。

二、线程池的优缺点

            (1)

谈到高并发必然离不开线程池,因为他有如下的优点:

               1.1、降低资源的消耗。通过利用已创建的线程,来降低创建和销毁带了的消耗

               1.2、当任务到达时候,不需要创建线程就可以立即执行。

               1.3、提高线程的可管理性。线程是稀缺资源,如果无限制的创建,不仅会消耗系统资源,还会降低系统的稳定性,使用线程池可以进行统一的分配,调优和监控。但是要做到合理的利用线程池,必须对其原理了如指掌。

           (2)线程池的缺点这里就不赘述了,可以 baidugoogle

三、如何编写线程池

先贴出代码

  线程池主要代码

import java.util.LinkedList;
import java.util.List;
 
public class NewThreadPool {
    volatile    int counter =0;
    private static int WORKNUM = 5;
    List<Runnable> taskQueue = new LinkedList<Runnable>();
 
    // 已处理的任务
    private static volatile int finished_task = 0;
    private WorkThread[] workThreads;
    private static NewThreadPool newThreadPool;
 
    private NewThreadPool(int workNum) {
        NewThreadPool.WORKNUM = workNum;
        // 定义一个工作线程数组
        workThreads = new WorkThread[workNum];
        for (int i = 0; i < workThreads.length; i++) {
            workThreads[i] = new WorkThread();
            workThreads[i].start();
        }
    }
 
    // 单例模式获得默认线程个数的线程池
    public static NewThreadPool getThreadPool() {
        return getNewThreadPool(NewThreadPool.WORKNUM);
    }
 
    // 获得传入参数个数的线程池,大小不能小于默认个数
    public static NewThreadPool getNewThreadPool(int work_num) {
        if (work_num <= 0) {
            work_num = NewThreadPool.WORKNUM;
        }
        if (null == newThreadPool) {
            newThreadPool = new NewThreadPool(work_num);
        }
        return newThreadPool;
    }
 
    //执行线程
    public void execute(Runnable task){
        synchronized (taskQueue) {
            taskQueue.add(task);
            taskQueue.notify();
        }
    }
     
    //批量执行线程任务
    public void execute(Runnable[] task){
        synchronized (taskQueue) {
            for(Runnable t : task ){
                taskQueue.add(t);
                taskQueue.notify();
            }
        }
    }
    public void execute(List<Runnable>task){
        synchronized (taskQueue) {
            for(Runnable t : task){
                taskQueue.add(t);
                taskQueue.notify();
            }
        }
    }
    //返回工作线程的个数
    public int getWorkedThreadNumbers(){
        return WORKNUM;
    }
    //返回已经完成的线程任务
    public int getFinishedTaskNumbers(){
        return finished_task;
    }
     
    //返回还没有完成任务的的线程个数
    public int getWaitTaskNumbers(){
        return taskQueue.size();
    }
     
    //销毁线程池方法,等到所有线程都完成之后才会销毁
    public void destory(){
        while(!taskQueue.isEmpty()){
            try {
                Thread.sleep(10);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        for(int i=0;i<WORKNUM;i++){
            workThreads[i].stopWorker();
            workThreads[i] = null;
        }
        newThreadPool = null;
        taskQueue.clear();
    }
    // 覆盖toString方法,返回线程池信息:工作线程个数和已完成任务个数
        @Override
        public String toString() {
            return "WorkThread number:" + WORKNUM + "  finished task number:"
                    + finished_task + "  wait task number:" + getWaitTaskNumbers();
        }
     
    // 工作线程
    private class WorkThread extends Thread {
        private boolean isRunning = true;
        @Override
        public void run() {
             
            Runnable r = null;
            while (isRunning) {
                synchronized (taskQueue) {
                    while (isRunning && taskQueue.isEmpty()) {
                        try {
                            taskQueue.wait(20);
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                    }
                    // 由于是队列,取第0个
                    if (!taskQueue.isEmpty()) {
                        r = taskQueue.remove(0);
                    }
                }
                if (null != r) {
                    r.run();
                    //stopWorker();
                }
                System.out.println(Thread.currentThread().getName() + "------------" + counter++  +"-----" + getWaitTaskNumbers());
                finished_task++;
                r = null;
            }
        }
        // 停止工作,让该线程自然执行完run方法,自然结束
        public void stopWorker() {
            isRunning = false;
        }
    }
}

以及测试demo

//测试线程池
public class TestThreadPool {
    public static void main(String[] args) {
        // 创建3个线程的线程池
        NewThreadPool t = NewThreadPool.getNewThreadPool(10);
        t.execute(new Runnable[] { new Task(), new Task(), new Task() , new Task(), new Task(), new Task(), new Task(), new Task(), new Task(), new Task(), new Task(), new Task(), new Task(), new Task()});
        t.execute(new Runnable[] { new Task(), new Task(), new Task() , new Task(), new Task(), new Task(), new Task(), new Task(), new Task(), new Task(), new Task(), new Task(), new Task(), new Task(), new Task(), new Task()});
        System.out.println(t);
        //t.destory();// 所有线程都执行完成才destory
        System.out.println(t);
        t.execute(new Runnable[] { new Task(), new Task(), new Task() , new Task(), new Task(), new Task(), new Task(), new Task(), new Task(), new Task(), new Task(), new Task(), new Task(), new Task()});
     
    }
 
    // 任务类
    static class Task implements Runnable {
        private static volatile int i = 1;
 
        @Override
        public void run() {// 执行任务
            System.out.println("任务 " + (i++) + " 完成");
        }
    }
}

以上为线程池代码。参看了很多网友的博客,然后才理解了这个线程池的代码,然后按着理解写出了这个。如果发现有和网友代码有类似,不要惊奇,我是初学者请见谅。呵呵

(三)总结:

         在编写线程池的时候,我们需要有一个基本的思路。需要一个基本的思路,一个安全的线程队列用来存放线程。按照要求初始化默认数量的线程,并且启动它,让这些线程在等待队列中等待,然后当目标任务来时,将其唤醒获得锁然后处理目标任务。

         由于队列是不安全的,所以在线程添加到队列,和从队列中取出来的时候,都需要同步synchroniza,保证其安全。还有一个概念就是一旦线程池中run方法跑完,那么它的生命周期也就结束了。线程状态转换,参考 线程基础(详细介绍线程状态转换) ,所以再我们需要一个信号量,将工作线程的run方法中加上信号量,这样就可以保证,线程池中线程可以重用,只有当你销毁线程池的时候,所有线程才会销毁。

转载于:https://my.oschina.net/u/731676/blog/268379

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值