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

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

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

来个典型程序范例:

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

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();
            }
        }
    }
}
C hannel类,可以当做车间

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;
    }
}
R e questqueue可以当做桌子,是一个数量有限的请求队列。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.4
Worker-3executeRequest fromCNo.10
Worker-2executeRequest fromANo.6
Worker-1executeRequest fromBNo.5
Worker-0executeRequest fromCNo.11
Worker-4executeRequest fromCNo.12
Worker-2executeRequest fromANo.7
Worker-3executeRequest fromCNo.13
Worker-1executeRequest fromBNo.6
Worker-0executeRequest fromBNo.7
Worker-2executeRequest fromANo.8
Worker-3executeRequest fromCNo.15
Worker-4executeRequest fromCNo.14

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


发布了69 篇原创文章 · 获赞 76 · 访问量 8万+

猜你喜欢

转载自blog.csdn.net/sinat_23092639/article/details/53148468