《java并发编程的艺术》并发工具类

CountDownLatch

join:

public class CountDownLatchTest {
    public static void main(String[] args) throws InterruptedException {
        Thread parser1 = new Thread(new Runnable() {
            @Override
            public void run() {
                System.out.println("parser1 finish");
            }
        });

        Thread parser2 = new Thread(new Runnable() {
            @Override
            public void run() {
                System.out.println("parser2 finish");
            }
        });

        parser1.start();
        parser2.start();
        parser1.join();
        parser1.join();
        System.out.println("all parser finish");
    }
}

countDownLatch:

import java.util.concurrent.CountDownLatch;

public class CountDownLatchTest {

    static CountDownLatch c = new CountDownLatch(2);

    public static void main(String[] args) throws InterruptedException {
        new Thread(new Runnable() {
            @Override
            public void run() {
                System.out.println(1);
                c.countDown();
                System.out.println(2);
                c.countDown();
            }
        }).start();

        c.await();
        System.out.println(3);
    }
}

构造函数接收一个int类型的参数作为计数器,该参数作为等待的次数。

当我们调用countDown方法时,该参数减1,CountDownLatch的await方法会阻塞当前线程,直到参数为0.
await有一个带指定时间的方法:await(long time,TimeUnit unit);

CyclicBarrier

CyclicBarrier的字面意思是可循环的屏障。让一组线程到达一个屏障时被阻塞,直到最后一个线程到达屏障时,屏障才会开门,所有被屏障拦截的线程才会继续运行。

import java.util.concurrent.BrokenBarrierException;
import java.util.concurrent.CyclicBarrier;

public class CyclicBarrierTest {
    static CyclicBarrier c = new CyclicBarrier(2);
    public static void main(String[] args){
        Thread thread = new Thread(new Runnable() {
            @Override
            public void run() {
                try {
                    c.await();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                } catch (BrokenBarrierException e) {
                    e.printStackTrace();
                }
                System.out.println(1);
            }
        });

        thread.start();

        try {
            c.await();
        } catch (InterruptedException e) {
            e.printStackTrace();
        } catch (BrokenBarrierException e) {
            e.printStackTrace();
        }
        System.out.println(2);

    }
}

CyclicBarrier默认的构造方法是CyclicBarrier(int partier),其参数表示屏障拦截的线程数量,每个线程调用await方法告诉CyclicBarrier我已经到达屏障了,然后当前线程被阻塞。直到最后一个线程到达屏障时,屏障才会开门,所有被屏障拦截的线程才会继续运行。

CyclicBarrier还有一个构造函数CyclicBarrier(int parties,Runnable barrierAction),用于线程到达屏障时,优先执行barrierAction。

static CyclicBarrier c = new CyclicBarrier(5, new Before());

    public static void main(String[] args) {

        Runnable r = () -> {
            System.out.println("i am a thread");
            try {
                c.await();
            } catch (InterruptedException e) {
                e.printStackTrace();
            } catch (BrokenBarrierException e) {
                e.printStackTrace();
            }
        };

        Thread[] threads = new Thread[4];
        for (int i = 0; i < threads.length; i++) {
            threads[i] = new Thread(r);
            threads[i].start();
        }

        try {
            c.await();
        } catch (InterruptedException e) {
            e.printStackTrace();
        } catch (BrokenBarrierException e) {
            e.printStackTrace();
        }
        System.out.println("over");
    }

    static class Before implements Runnable {

        @Override
        public void run() {
            System.out.println("i am out of barrier");
        }
    }

运行结果:

i am a thread
i am a thread
i am a thread
i am a thread
i am out of barrier
over

CyclicBarrier的计数器可以使用reset()方法重置。

Semaphore

Semaphore信号量用来控制同时访问特定资源的线程数量,它通过协调各个线程,保证合理的使用公共资源。

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Semaphore;

public class SemaphoreTest {
    public static final int THREAD_COUNT = 30;
    private static ExecutorService threadPool = Executors.newFixedThreadPool(THREAD_COUNT);
    private static Semaphore s = new Semaphore(10);

    public static void main(String[] args){
        for (int i = 0; i < THREAD_COUNT; i++) {
            threadPool.execute(new Runnable() {
                @Override
                public void run() {
                    try {
                        s.acquire();
                        System.out.println("save data");
                        s.release();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            });
        }
        threadPool.shutdown();
    }
}

信号量可以用来控制并发量。首先线程使用Semaphore的acquire()方法获得一个许可证,使用完后调用release()方法归还许可证,拥有许可证的线程才可以执行。

Exchanger

Exchanger是一个线程间协作的工具类。提供了一个同步点,在这个同步点,两个线程可以交换彼此的数据。当第一个线程执行exchange()方法,它会一直等待第二个线程也执行exchange()方法,当两个线程都到达同步点时,线程可以交换数据。

Exchanger可以用于遗传算法,遗传算法需要选出两个人作为交配对象,这时候交换两个人的数据,并使用交叉规则得出2个交配结果。Exchanger也可以用于校对工作。

import java.util.concurrent.Exchanger;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class ExchangerTest {
    private static final Exchanger<String> ex = new Exchanger<>();
    private static ExecutorService threadPool = Executors.newFixedThreadPool(2);
    public static void main(String[] args){
        threadPool.execute(()->{
            String A = "银行流水A";
            try {
                ex.exchange(A);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        });

        threadPool.execute(()->{
            String B = "银行流水B";
            try {
                String A = ex.exchange("B");
                System.out.println("A录入:"+A);
                System.out.println("B录入:"+B);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }

        });

        threadPool.shutdown();
    }
}

猜你喜欢

转载自blog.csdn.net/sayWhat_sayHello/article/details/81144353