Java Concurrent Programming 第四篇

一:CountDownLatch

(等待多线程完成)
//构造入参2。这个参数表示需要计数2次,这个CDL才结束
CountDownLatch c = new CountDownLatch(2);

//计数  这个例子中总共需要调用两次countDown(),计数才结束
c.countDown()

//在主线程中调用,调用了这个方法后如果c没有计数到0则阻塞,直到计数为0,唤醒线程
c.await()

代码:

    CountDownLatch c = new CountDownLatch(2);

        Thread t1 = new Thread(new Runnable() {
            public void run() {
                try {
                    System.out.println("线程1开始执行!");
                    Thread.sleep(3000);
                    System.out.println("线程1结束执行!");
                    c.countDown();
                } catch (InterruptedException e) {

                   c.countDown();

                }
            }
        });

        Thread t2 = new Thread(new Runnable() {
            public void run() {
                try {
                    System.out.println("线程2开始执行!");
                    Thread.sleep(5000);
                    System.out.println("线程2结束执行!");
                    c.countDown();
                } catch (InterruptedException e) {

                  c.countDown();

                }
            }
        });
        t1.start();
        t2.start();
        try {
            System.out.println("开始等待线程1、2结束");
            c.await();
            System.out.println("线程1、2结束");
        } catch (InterruptedException e) {

        }

二:CyclicBarrier

让一组线程到达一个屏障时被阻塞,直到最后一个线程到达屏障时,屏障才会开门,所有被阻塞的线程才能执行下去。

    CyclicBarrier c = new CyclicBarrier(3);
        Thread t1 = new Thread(new Runnable() {
            public void run() {
                try {
                    System.out.println("线程1开始执行!");
                    Thread.sleep(3000);
                    System.out.println("线程1结束执行!");
                    c.await();
                } catch (Exception e) {

                }
            }
        });

        Thread t2 = new Thread(new Runnable() {
            public void run() {
                try {
                    System.out.println("线程2开始执行!");
                    Thread.sleep(5000);
                    System.out.println("线程2结束执行!");
                    c.await();
                } catch (Exception e) {

                }
            }
        });
        t1.start();
        t2.start();

        System.out.println("开始等待线程1、2结束");
        c.await();
        System.out.println("线程1、2结束");

三:Semaphore

Semaphore(信号量)是用来控制同时访问特定资源的线程数量。

Semaphore 的构造方法需要传入一个参数,如 new Semaphore(10),
表示最多有10个线程可以获取到信号量,10个之后的线程再尝试获取时就会被阻塞。
获取信号量使用:s.acquire()方法;
释放信号量使用:s.release()方法。
只有前边的线程释放掉后,后面的线程(10个之后)才能被唤醒,重新获取信号量。它可以用来控制同时 运行的线程的数目。

 private static Connection instance = new Connection();
    private Semaphore semaphores = new Semaphore(10,true);
    private int connections = 0;

    private Connection() {
    }

    public static Connection getInstance() {
        return instance;
    }

    public void connect() {
        try {
            semaphores.acquire();
            doConnect();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }finally {
            semaphores.release();
        }
    }

    private void doConnect() {
        synchronized (this) {
            connections ++;
            System.out.println("current get connections is : " + connections);
        }
        try {
            Thread.sleep(2000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        synchronized (this) {
            connections --;
            System.out.println("after release current  connections is : " + connections);
        }
    }
}


public class Test1 {

    public static void main(String[] args) throws Exception {
        
         ExecutorService executorService = Executors.newCachedThreadPool();
            for (int i = 0; i < 200; i++) {
                executorService.submit(new Runnable() {
                    @Override
                    public void run() {
                        Connection.getInstance().connect();
                    }
                });
            }
            executorService.shutdown();
            executorService.awaitTermination(1, TimeUnit.DAYS);
        
    }

四:Exchanger

Exchanger可以用于线程间交换信息。它提供一个同步点,当两个线程都到达这个同步点时,它们的信息交换。只有一个到达时,它先等待,直到另一个线程也到达。

 
    ExecutorService threadPool = Executors.newFixedThreadPool(2);
    final Exchanger<String> exchanger = new Exchanger<String>();

    threadPool.execute(new Runnable() {
        public void run() {
            try {
                String b = exchanger.exchange("hello,anyone");
                System.out.println("thread1 reviced :" + b);
            } catch (Exception e) {

            }
        }
    });

    threadPool.execute(new Runnable() {
        public void run() {
            try {
                String a = exchanger.exchange("hello,anybody");
                System.out.println("thread2 reviced :" + a);
            } catch (Exception e) {

            }
        }
    });

输出:

thread2 reviced :hello,anyone
thread1 reviced :hello,anybody

五:fork/join框架

    public static void main(String[] args) {
        
        long l=System.currentTimeMillis();
        ForkJoinPool forkJoinPool=new ForkJoinPool();//实现ForkJoin 就必须有ForkJoinPool的支持
        ForkJoinTask<Long> task=new  ForkJoinWork(0l,1000000l);
        
        Long invoke=forkJoinPool.invoke(task);
        long l1 = System.currentTimeMillis();
        System.out.println("invoke = " + invoke+"  time: " + (l1-l));

    }

public class ForkJoinWork  extends RecursiveTask<Long> {
    
        private Long start;//起始值
        private Long end;//结束值
        public static final  Long critical = 100000L;//临界值

        public ForkJoinWork(Long start, Long end) {
            this.start = start;
            this.end = end;
        }

        @Override
        protected Long compute() {
            //判断是否是拆分完毕
            Long lenth = end - start;
            if(lenth<=critical){
                //如果拆分完毕就相加
                Long sum = 0L;
                for (Long i = start;i<=end;i++){
                    sum += i;
                }
                return sum;
            }else {
                //没有拆分完毕就开始拆分
                Long middle = (end + start)/2;//计算的两个值的中间值
                ForkJoinWork right = new ForkJoinWork(start,middle);
                right.fork();//拆分,并压入线程队列
                ForkJoinWork left = new ForkJoinWork(middle+1,end);
                left.fork();//拆分,并压入线程队列
                //合并
                return right.join() + left.join();
            }
        }
}

六:

1:减少锁的粒度、范围;

2:注意加锁的顺序;

3:使用超时时间锁:trylock

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值
>