Use of ExecutorCompletionService, Exchanger, Phaser of java concurrent package

ExecutorCompletionService class

When we submit a group of concurrently executed tasks through Executor, and hope to get the results immediately after each task is completed, there are two ways to take:

  • method one:

Save a group of futures through a list, and then train the group of futures in a loop until each future is completed. If we do not want the situation where the results of the tasks completed later are not obtained in time due to the blocking of the tasks in the front, then the timeout period needs to be set to 0 when calling the get method. 

static class Task implements Callable<String> {

        private int i;

        public Task(int i) {
            this.i = i;
        }

        @Override
        public String call() throws Exception {
            Thread.sleep(1000);
            return Thread.currentThread().getName() + "执行完任务" + i;
        }
    }
 private static int numThread = 5;
   //手动创建线程池
        ThreadPoolExecutor threadPoolExecutor =
                new ThreadPoolExecutor(5, 15, 200, TimeUnit.MILLISECONDS, new LinkedBlockingDeque<>(30));
        List<Future<String>> resultList = new ArrayList<>(5);
        for (int i = 1; i <= numThread; i++) {
            Future<String> future = threadPoolExecutor.submit(new Task(i));
            resultList.add(future);
        }

        while (numThread > 0) {
            if (!CollectionUtils.isEmpty(resultList)) {
                for (Future<String> future : resultList) {
                    String result = null;
                    try {
                        result = future.get(0, TimeUnit.SECONDS);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    } catch (ExecutionException e) {
                        e.printStackTrace();
                    } catch (TimeoutException e) {
                        // 超时异常直接忽略
                    }
                    if (!StringUtils.isEmpty(result)) {
                        resultList.remove(future);
                        numThread--;
                        System.out.println(result);
                        // 此处必须break,否则会抛出并发修改异常。(也可以通过将futureList声明为CopyOnWriteArrayList类型解决)
                        break;
                    }
                }
            }
        }
  • Way two:

The first method is more cumbersome. By using ExecutorCompletionService, you can achieve the most simplified code.

  //手动创建线程池
		ThreadPoolExecutor threadPoolExecutor =
				new ThreadPoolExecutor(5, 15, 200, TimeUnit.MILLISECONDS, new LinkedBlockingDeque<>(30));
        ExecutorCompletionService<String> executorCompletionService = new ExecutorCompletionService<>(threadPoolExecutor);
        for (int i = 1; i <= numThread; i++) {
            executorCompletionService.submit(new Task(i));
		}
        for(int i=1;i<=numThread;i++){
			try {
				System.out.println(executorCompletionService.take().get());
			} catch (InterruptedException e) {
				e.printStackTrace();
			} catch (ExecutionException e) {
				e.printStackTrace();
			}
		}
        threadPoolExecutor.shutdown();

 operation result:

Exchanger class

Exchanger is an encapsulation tool class provided by JDK 1.5 to exchange data between two worker threads. Simply put, when a thread wants to exchange data with another thread after completing a certain transaction, the first one will take out the data first. The thread will wait for the second thread until the second thread arrives with the data to exchange the corresponding data with each other. Defined as Exchanger<V>a generic type, where V represents the exchangeable data type, provide external interfaces is very simple, as follows:

  • Exchanger():No parameter construction method.

  • V exchange(V v):Wait for another thread to reach this exchange point (unless the current thread is interrupted), then transfer the given object to the thread and receive the thread's object.

  • V exchange(V v, long timeout, TimeUnit unit):Wait for another thread to reach this exchange point (unless the current thread is interrupted or the specified waiting time is exceeded), and then transfer the given object to the thread and receive the thread's object.

It can be seen that when a thread reaches the exchange call point, if other threads have already called this method before, the other threads will be scheduled to wake up and exchange objects with it, and then return separately; if other threads have not reached the exchange point, The current thread will be suspended until the other threads arrive and will not complete the exchange and return normally, or the current thread will be interrupted or return over time.

static class Producer extends Thread {
		private Exchanger<Integer> exchanger;
		private static int data = 0;
		Producer(String name, Exchanger<Integer> exchanger) {
			super("Producer-" + name);
			this.exchanger = exchanger;
		}

		@Override
		public void run() {
			for (int i=1; i<5; i++) {
				try {
					TimeUnit.SECONDS.sleep(1);
					data = i;
					System.out.println(getName()+" 交换前:" + data);
					data = exchanger.exchange(data);
					System.out.println(getName()+" 交换后:" + data);
				} catch (InterruptedException e) {
					e.printStackTrace();
				}
			}
		}
	}

	static class Consumer extends Thread {
		private Exchanger<Integer> exchanger;
		private static int data = 0;
		Consumer(String name, Exchanger<Integer> exchanger) {
			super("Consumer-" + name);
			this.exchanger = exchanger;
		}

		@Override
		public void run() {
			while (true) {
				data = 0;
				System.out.println(getName()+" 交换前:" + data);
				try {
					TimeUnit.SECONDS.sleep(1);
					data = exchanger.exchange(data);
				} catch (InterruptedException e) {
					e.printStackTrace();
				}
				System.out.println(getName()+" 交换后:" + data);
			}
		}
	}
	public static void main(String[] args) throws InterruptedException {
	Exchanger<Integer> exchanger = new Exchanger<Integer>();
		new Producer("", exchanger).start();
		new Consumer("", exchanger).start();
		TimeUnit.SECONDS.sleep(7);
		System.exit(-1);

    }

operation result: 

 Phaser class

The java multithreading technology provides the Phaser tool class. Phaser stands for "phaser", which is used to solve the situational problem of controlling multiple threads to complete tasks together in phases. Its function is more flexible than CountDownLatch and CyclicBarrier. For example, there is a question: 5 students take the exam together, there are three questions in total, all students are required to start the exam when all students have completed the first question, and students can Continue to do the second question. After all students have completed the second question, they can do the third question. All students have completed the third question before the exam ends. Analyze this question: This is a multi-threaded (5 students) question in stages (exam exam, completion of the first question, completion of the second question, and completion of the third question), so it is very suitable to use Phaser to solve this problem.

package concurrent.phaser;

import java.util.concurrent.Phaser;

/**
 * 比赛阶段器
 */
public class GamePhaser extends Phaser {

    /**
     * 当一个阶段的所有线程都到达时 , 执行该方法, 此时 phase自动加1
     * @param phase
     * @param registeredParties
     * @return
     */
    @Override
    protected boolean onAdvance(int phase, int registeredParties) {
        switch (phase) {
            case 0 :
                System.out.println("预赛完成");
                return false;
            case 1:
                System.out.println("初赛完成");
                return false;
            case 2:
                System.out.println("决赛完成");
                return false;
            default:
                return true;
        }
    }
}

 

package concurrent.phaser;

import java.util.concurrent.Phaser;

/**
 * 运动员类
 */
public class Runner implements Runnable {

    private Phaser phaser;

    public Runner(Phaser phaser) {
        this.phaser = phaser;
    }

    @Override
    public void run() {
        /**
         * 参加预赛
         */
        System.out.println("选手-"+Thread.currentThread().getName()+":参加预赛");
        /**
         * 预赛阶段-----执行这个方法的话会等所有的选手都完成了之后再继续下面的方法
         */
        phaser.arriveAndAwaitAdvance();
        /**
         * 参加初赛
         */
        System.out.println("选手-"+Thread.currentThread().getName()+":参加初赛");
        /**
         * 初赛阶段-----执行这个方法的话会等所有的选手都完成了之后再继续下面的方法
         */
        phaser.arriveAndAwaitAdvance();
        /**
         * 参加决赛
         */
        System.out.println("选手-"+Thread.currentThread().getName()+":参加决赛");
        /**
         * 决赛阶段-----执行这个方法的话会等所有的选手都完成了之后再继续下面的方法
         */
        phaser.arriveAndAwaitAdvance();
    }
}

 

package concurrent.phaser;

/**
 * 比赛开始
 */
public class RunnerGame {
    public static void main(String[] args) {
        int runnerNum = 4;

        GamePhaser gamePhaser = new GamePhaser();
        /**
         * 注册一次表示phaser维护的线程个数
         */
        gamePhaser.register();
        for (int i = 0; i < runnerNum;  i++ ) {
            /**
             * 注册一次表示phaser维护的线程个数
             */
            gamePhaser.register();
            new Thread(new Runner(gamePhaser)).start();

        }
        /**
         * 后续阶段主线程就不参加了
         */
        gamePhaser.arriveAndDeregister();

    }
}

operation result:

Players -Thread-0: participate in the preliminaries
players -Thread-1: participate in the preliminaries
players -Thread-3: participate in the preliminaries
players -Thread-2: participate in the preliminaries
preliminaries complete
player -Thread-2: participate in the preliminary round
players -Thread-0: to participate in the preliminary round
Contestant-Thread-3: Participate in the preliminary
contest Contestant-Thread-1: Participate in the preliminary contest Preliminary contest is
completed
Contestant-Thread-1: Participate in the final
Contestant-Thread-2: Participate in the final
Contestant-Thread-0: Participate in the final
Contestant-Thread-3: Participate in the final
Finals completed

 

Guess you like

Origin blog.csdn.net/qq_31905135/article/details/108995394