Several ways of obtaining data by java multithreading

Posted by LiamBailey on Wed, 08 Sep 2021 21:46:31 +0200

The several ways we listed above to obtain multi-threaded execution results are realized through different technical methods, and the producer consumer model itself has nothing to do with the technical implementation you use. Students who have been in contact with multi-threaded development should understand it;

The producer consumer model is shown in the figure below

Producer consumer pattern is a multi-threaded design pattern that can decouple and synchronize production threads, consumption threads and data sets. One or a group of producer threads are responsible for producing data to the data queue, that is, the thread execution results; In addition, one or a group of consumer threads are responsible for consuming and processing data in the data queue. Producer threads and consumer threads are not directly related to each other. Data interaction is through the data queue. This mode can solve the problems of thread synchronization and safety in multi-threaded development to a certain extent, At the same time, the program will also look clearer and easier to understand;

Of course, for a perfect producer consumer model, we need to consider many other aspects,   However, the following two elements are the most critical:

1. Thread safety means that producers and consumers perform read-write operations respectively. Especially when there are multiple production threads and consumption threads, there must be concurrent data read-write operations. Therefore, the data queue must ensure thread safety;

2. The coordination between production and consumption, whether the production thread stops writing when the data queue is full, and whether the consumption thread stops consuming when the data queue is empty, on the one hand, we need to consider your application scenario and unnecessary performance waste;

Let's look at the basic code implementation

First, define a global data queue. Here, I use the blocking queue ArrayBlockingQueue provided by JDK. Here, I can also directly use the completionService mentioned above. Of course, I can also use other thread safe data sets or define and implement them myself. However, note that no matter which one is used, we should pay attention to the above two key elements, In normal use, the blocking queue encapsulated by JDK has basically met the requirements;

public class Container {
    public static ArrayBlockingQueue<Result> arrayBlockingQueue = new ArrayBlockingQueue<>(100);//Here, it is best to evaluate a threshold according to the system load to avoid OOM problems
}

Producer thread implementation, whether to use put or offer for queue data insertion is adjusted in combination with application scenarios

public class ProducerThread extends Thread {
    
    public void run() {    
        try {
            Thread.sleep(1000*3);//Simulation program execution
            Result result = new Result();
            result.setValue(Thread.currentThread().getName()+"After the thread is executed, the result is output");
            Container.arrayBlockingQueue.put(result);//Blocking when the maximum threshold of blocking queue is exceeded, blocking all the time
//            if(!Container.arrayBlockingQueue.offer(result, 5, TimeUnit.SECONDS)) {/ / failed to queue data within the specified time
//                System.err.println("data queue failed");
//            }
        } catch (InterruptedException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }

}

The consumer thread is implemented. The consumer thread is a resident thread. When there is no data in the queue, the thread is blocked

public class ConsumerThread extends Thread {
    
    public void run() {
         while (!this.isInterrupted()) {
             try {
                Result result = Container.arrayBlockingQueue.take();//Consume when there is data, and wait when there is no data
                System.out.println(result.getValue());
            } catch (InterruptedException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
         }
    }
}

  Start the production thread and consumption thread at the same time in the main thread

public class MainThread  {
    public static void main(String[] args) {
        
        ExecutorService exec = new ThreadPoolExecutor(10, 20, 1000, TimeUnit.MILLISECONDS,
                new ArrayBlockingQueue<Runnable>(5), Executors.defaultThreadFactory(),
                new ThreadPoolExecutor.CallerRunsPolicy());
        
        for(int i=0;i<100;i++) {//Use thread pool to simulate producer production data
            exec.execute(new ProducerThread());
        }
        
        for(int i=0;i<2;i++) {//Start two consumer threads
            new ConsumerThread().start();
        }
    }
}

The consumer thread will poll to get the results executed by the producer thread and put into the blocking queue

The pool-1-thread-13 thread finishes executing and outputs the result
After the execution of pool-1-thread-2 thread, the result is output
After the execution of pool-1-thread-1 thread, the result is output
After the execution of pool-1-thread-10 thread, the result is output
After the execution of pool-1-thread-9 thread, the result is output
The pool-1-thread-15 thread finishes executing and outputs the result
After the execution of pool-1-thread-4 thread, the result is output
After the execution of pool-1-thread-5 thread, the result is output
After the execution of pool-1-thread-8 thread, the result is output
pool-1-thread-12 the thread finishes executing and outputs the result
The pool-1-thread-16 thread finishes executing and outputs the result
.....................................................
.....................................................

https://www.cnblogs.com/dafanjoy/p/14505058.html

Topics: Java