java多线程设计模式Worker Thread(线程池)

来源:互联网 发布:寺库网是正品吗 知乎 编辑:程序博客网 时间:2024/06/03 05:07

想象一个场景,一个工厂在生产玩具,在一个车间里,有几个工人,每次生产部件准备好车间外的人就将部件放到车间的一个桌子上,工人每次做完一个玩具就从桌子上取部件。在这里,注意到,部件并不是直接交给工人的,另外一点,工人并不是做完一个部件就回家换个新人,后者在现实有点滑稽,但是在程序中却对应一个典型的线程使用方法:线程池。

所谓线程池,就是对线程的复用,当线程执行完任务之后就继续取其他任务执行,而不是销毁启动新线程执行其他任务。因为线程的启动对于系统性能开销比较大,所以这样对于系统性能的提高很有好处。

来个典型程序范例:

   首先是请求,即玩具的部件

public class Request {    private final String name;    private final int number;    private static final Random random = new Random();    public Request(String name, int number) {        this.name = name;        this.number = number;    }    public void execute(){        System.out.println(Thread.currentThread().getName()+"execute"+this);        try {            Thread.sleep(1000);        } catch (InterruptedException e) {            e.printStackTrace();        }    }    @Override    public String toString() {        return "Request from" + name + "No."+ number;    }

也就是拥有name和number并且execute的时候打印出字段的一个简单类。

然后是ClientThread,负责将请求放入RequestQueue中,即将部件放到桌子上。

public class ClientThread extends  Thread{    private final Channel channel;    private static final Random random = new Random();    public ClientThread(Channel channel,String name) {        super(name);        this.channel = channel;    }    @Override    public void run() {        for (int i = 0; true; i++) {            Request request = new Request(getName(),i);            channel.putRequest(request);            try {                Thread.sleep(random.nextInt(1000));            } catch (InterruptedException e) {                e.printStackTrace();            }        }    }}
Channel类,可以当做车间

public class Channel {    private static final int MAX_REQUEST = 100;    private final Request[] requestQueue;    private int tail;    private int head;    private int count;    private final WorkerThread[] thraedPool;    public Channel(int thraedSize) {        this.requestQueue = new Request[MAX_REQUEST];        head = 0;        tail = 0;        count = 0;        thraedPool = new WorkerThread[thraedSize];        for (int i = 0; i < thraedPool.length; i++) {            thraedPool[i] = new WorkerThread("Worker-"+ i,this);        }    }    public void startWorker(){        for (int i = 0; i < thraedPool.length; i++) {            thraedPool[i].start();        }    }    public synchronized void putRequest(Request request){        while (count >= requestQueue.length){                try {                    wait();                } catch (InterruptedException e) {                    e.printStackTrace();                }        }        requestQueue[tail] = request;        tail = (tail+1)%requestQueue.length;        count++;        notifyAll();    }    public synchronized Request takeRequest(){        while (count <= 0){            try {                wait();            } catch (InterruptedException e) {                e.printStackTrace();            }        }        Request request = requestQueue[head];        head = (head + 1)%requestQueue.length;        count--;        notifyAll();        return  request;    }}
Requestqueue可以当做桌子,是一个数量有限的请求队列。threadPool是一个工人线程的数组,这就是一个线程池。在这里提供了putRequest和takeRequest方法,分别是往请求队列放入请求和取出请,这里使用了上一篇博文讲到的生产者消费者模式 java多线程设计模式之消费者生产者模式。确保了WorkerThread和ClientThread之间可以友好合作。

工人线程:

public class WorkerThread extends Thread{    private final Channel channel;    public WorkerThread(String name,Channel channel) {        super(name);        this.channel = channel;    }    @Override    public void run() {        while (true){            Request request = channel.takeRequest();            request.execute();        }    }}
这里就是一个不断从请求队列中取出请求然后执行请求的过程,保证了工人线程的复用,并不会执行完一个请求任务就销毁。

最后是Main:

public class Main {    public static void main(String[] args){        Channel channel = new Channel(5);        channel.startWorker();        new ClientThread(channel,"A").start();        new ClientThread(channel,"B").start();        new ClientThread(channel,"C").start();    }}

结果:
Worker-4executeRequest fromBNo.4Worker-3executeRequest fromCNo.10Worker-2executeRequest fromANo.6Worker-1executeRequest fromBNo.5Worker-0executeRequest fromCNo.11Worker-4executeRequest fromCNo.12Worker-2executeRequest fromANo.7Worker-3executeRequest fromCNo.13Worker-1executeRequest fromBNo.6Worker-0executeRequest fromBNo.7Worker-2executeRequest fromANo.8Worker-3executeRequest fromCNo.15Worker-4executeRequest fromCNo.14

可以看出线程执行任务的线程就是WorkerThread1,2,3,4,5五个,它们不断执行来自ClientThread A,B,C的请求任务。


1 0
原创粉丝点击
热门问题 老师的惩罚 人脸识别 我在镇武司摸鱼那些年 重生之率土为王 我在大康的咸鱼生活 盘龙之生命进化 天生仙种 凡人之先天五行 春回大明朝 姑娘不必设防,我是瞎子 2岁宝宝语言退化怎么办 两周宝宝嗓子哑怎么办 幼儿园孩子上课爱说话老师怎么办 一岁宝宝不会爬怎么办 孩子说话不太清楚怎么办 十一个月宝宝不爱吃饭怎么办 14个月宝宝不爱吃饭怎么办 一岁宝宝喜欢哭怎么办 4岁儿童不会说话怎么办 8个月宝宝37.5度怎么办 8个月婴儿37.5度怎么办 5个月宝宝38度怎么办 5个月宝宝发烧怎么办 五个月小孩38度怎么办 宝宝3岁还不会说话 怎么办 两岁宝宝流口水厉害怎么办 两周宝宝不说话怎么办 两岁宝宝说话有点口吃怎么办 一周岁的宝宝脾气不好怎么办 九个月的宝宝脾气不好怎么办 两岁宝宝脾气不好怎么办 2岁宝宝脾气不好怎么办 3岁宝宝脾气不好怎么办 脾气不好吓到宝宝了怎么办 四个月宝宝脾气不好怎么办 5岁说话不清楚该怎么办 小孩快上幼儿园了不怎么说话怎么办 四岁宝宝吐字不清楚怎么办 孕28周胎儿腿短怎么办 b超显示腿短怎么办 2岁多宝宝不愿意说话怎么办 6岁儿童咬字不清怎么办 两岁宝宝爱看电视怎么办 两岁宝宝喜欢看电视怎么办 三岁宝宝说话不清晰怎么办 儿子快四岁了说话不清楚怎么办 儿子快三岁了说话不清楚怎么办 2岁宝宝受刺激了怎么办 一岁的宝宝口臭怎么办 古话说小孩牙齿掉了怎么办 宝宝三岁胆子小怎么办