1. The Worker Thread model

In Worker Thread mode, Worker threads retrieve work one by one and process it. When all work is completed, Worker threads wait for new work to arrive.

The Worker Thread pattern is also known as the Background Thread pattern, and can also be called the Thread Pool pattern in terms of where multiple Worker threads are stored.

2. Roles in Worker Thread mode

1.Client

Create a Request representing a work Request and pass it to a Channel. In the sample program, ClientThread corresponds to this role.

2.Channel

The Channel role receives the Request from the Client and passes it to the Worker. In the sample program, a Channel corresponds to this role.

3. I’m a Worker.

The Worker role retrieves a Request from a Channel and works on it. When a job is completed, it proceeds to retrieve another Request. In the example application, the WorkerThread is the role.

4.Request

The Request role is the role that represents the work. The Request role holds the information necessary to perform the work. In the example program, Request is equivalent to this role.

3. Application scenarios of Worker threads

Imagine a scene, a factory is making toys, in a workshop, there are several workers, each time the production part is ready, someone outside the workshop puts the part on a table in the workshop, and the worker takes the part off the table every time he makes a toy. Note here that the parts are not handed to the worker directly, and that the worker does not finish a part and then go home and get a new one, which is a bit funny in real life, but in the program corresponds to a typical way of using threads: thread pools.

The so-called thread pool is the reuse of threads, after the completion of the task to continue to take other tasks, rather than destroy and start a new thread to perform other tasks. Since starting a thread is expensive for system performance, it is beneficial to improve system performance.

4.Worker Thread program example

The first is the request, the parts of the toy


public class Request {

    private final String name;
    private final int number;

    public Request(String name, int number) {
        this.name = name;
        this.number = number;
    }

    public void execute(a){
        System.out.println(Thread.currentThread().getName()+" executed "+this);
    }
    @Override
    public String toString(a) {
        return "Request=> " + "No." + number + " Name."+ name; }}Copy the code

A simple class that has a name and number and prints fields when execute.

ClientThread, which is responsible for putting requests into the RequestQueue, putting the parts on the table.


public class ClientThread extends Thread {

    private static final Random random = new Random(System.currentTimeMillis());

    private final Channel channel;

    public ClientThread(String name, Channel channel) {
        super(name);
        this.channel = channel;
    }

    @Override
    public void run(a) {
        try {

            for (int i = 0; true; i++) {
                Request request = new Request(getName(),i);
                this.channel.put(request);
                Thread.sleep(random.nextInt(1 _000)); }}catch (Exception e) {

        }
    }
}
Copy the code

The Channel class can be used as a workshop


public class Channel {

    private final static int MAX_REQUEST = 100;

    private final Request[] requestQueue;
    private final WorkerThread[] workerPool;
    private int head;
    private int tail;
    private int count;

    public Channel(int workers) {

        this.requestQueue = new Request[MAX_REQUEST];
        this.head = 0;
        this.tail = 0;
        this.count = 0;
        this.workerPool = new WorkerThread[workers];
        this.init();
    }

    private void init(a) {
        for (int i = 0; i < workerPool.length; i++) {
            workerPool[i] = new WorkerThread("Worker-" + i, this); }}/** * push switch to start all of worker to work */
    public void startWorker(a) {
        Arrays.asList(workerPool).forEach(WorkerThread::start);

// List
      
        workerThreads = Arrays.asList(workerPool);
      
//
// workerThreads.stream().forEach(WorkerThread::start);
    }

    public synchronized void put(Request request) {
        while (count >= requestQueue.length) {
            try {
                this.wait();
            } catch(InterruptedException e) { e.printStackTrace(); }}this.requestQueue[tail] = request;
        this.tail = (tail + 1) % requestQueue.length;
        this.count++;
        this.notifyAll();
    }

    public synchronized Request take(a) {
        while (count <= 0) {
            try {
                this.wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        Request request = this.requestQueue[head];
        this.head = (this.head + 1) % this.requestQueue.length;
        this.count--;
        this.notifyAll();
        returnrequest; }}Copy the code

A Requestqueue, which can be used as a table, is a queue with a limited number of requests. A threadPool is an array of worker threads, which is a threadPool. PutRequest and takeRequest methods are provided to put and retrieve requests to the request queue, respectively, using the consumer-producer pattern of the Java multithreaded design pattern described in the previous blog post. This ensures friendly cooperation between WorkerThread and ClientThread.

Worker thread:


public class WorkerThread extends Thread {

    private static final Random random = new Random(System.currentTimeMillis());
    private final Channel channel;

    public WorkerThread(String name, Channel channel) {
        super(name);
        this.channel = channel;
    }

    @Override
    public void run(a) {
        while (true) {
            channel.take().execute();

            try {
                Thread.sleep(random.nextInt(1 _000));
            } catch(InterruptedException e) { e.printStackTrace(); }}}}Copy the code

This is a process of continually fetching requests from the request queue and executing them, ensuring that worker threads are reused and not destroyed after each request task is executed.

And finally Main:


public class WorkerClient {

    public static void main(String[] args) {
        final Channel channel = new Channel(5);
        channel.startWorker();

        new ClientThread("Alex", channel).start();
        new ClientThread("Jack", channel).start();
        new ClientThread("William", channel).start(); }}Copy the code

Results:


Worker-4 executed Request=> No. 0  Name.Alex
Worker-2 executed Request=> No. 0  Name.Jack
Worker-3 executed Request=> No. 0  Name.William
Worker-4 executed Request=> No1.  Name.Jack
Worker-0 executed Request=> No1.  Name.William
Worker-3 executed Request=> No2.  Name.Jack
Worker-2 executed Request=> No1.  Name.Alex
Worker-4 executed Request=> No2.  Name.William
Worker-1 executed Request=> No3.  Name.Jack
Worker-3 executed Request=> No2.  Name.Alex
Worker-4 executed Request=> No3.  Name.William
Worker-0 executed Request=> No4.  Name.Jack
Worker-0 executed Request=> No3.  Name.Alex
Worker-1 executed Request=> No. 5  Name.Jack
Worker-3 executed Request=> No4.  Name.William
Worker-1 executed Request=> No6.  Name.Jack
Worker-2 executed Request=> No4.  Name.Alex
Worker-3 executed Request=> No7.  Name.Jack
Worker-0 executed Request=> No. 5  Name.William
Worker-1 executed Request=> No. 5  Name.Alex
Worker-4 executed Request=> No8.  Name.Jack
Worker-2 executed Request=> No6.  Name.Alex
Worker-0 executed Request=> No7.  Name.Alex
Worker-4 executed Request=> No8.  Name.Alex
Worker-2 executed Request=> No6.Name. William omit...Copy the code

WorkerThread1,2,3,4, and 5 are the threads that perform tasks requested by ClientThreads Alex,Jack, and William.