JAVA并发容器与并发工具类

1、JAVA并发容器

  1. ConcurrentHashMap :线程安全的Map。
  2. ConcurrentLinkedQueue:线程安全非阻塞队列。采用先进先出的规
    则对节点进行排序,当我们添加一个元素的时候,它会添加到队列的尾部;当我们获取一个元素时,它会返回队列头部的元素。它采用了“wait-free”算法(即CAS算法)来实现。
  3. ArrayBlockingQueue:是一个用数组实现的有界阻塞队列。此队列按照先进先出(FIFO)的原则对元素进行排序
  4. LinkedBlockingQueue:是一个用链表实现的有界阻塞队列。此队列的默认和最大长度为Integer.MAX_VALUE。此队列按照先进先出的原则对元素进行排序。
  5. PriorityBlockingQueue:是一个支持优先级的无界阻塞队列。默认情况下元素采取自然顺序升序排列。可以自定义类实现compareTo()方法来指定元素排序规则,或初始化PriorityBlockingQueue时,指定构造参Comparator来对元素进行排序。需要注意的是不能保证同优先级元素的顺序。
  6. DelayQueue:是一个支持延时获取元素的无界阻塞队列。

应用场景如下:
·缓存系统的设计:可以用DelayQueue保存缓存元素的有效期,使用一个线程循环
查询DelayQueue,一旦能从DelayQueue中获取元素时,表示缓存有效期到了。
·定时任务调度:使用DelayQueue保存当天将会执行的任务和执行时间,一旦从
DelayQueue中获取到任务就开始执行,比如TimerQueue就是使用DelayQueue实现的。

实现方式:
DelayQueue队列的元素必须实现Delayed接口。我们可以参考
ScheduledThreadPoolExecutor里ScheduledFutureTask类的实现。

  1. LinkedTransferQueue:LinkedTransferQueue是一个由链表结构组成的无界阻塞TransferQueue队列。相对于其他阻塞队列,LinkedTransferQueue多了tryTransfer和transfer方法。

transfer:如果当前有消费者正在等待接收元素(消费者使用take()方法或带时间限制的poll()方法时),transfer方法可以把生产者传入的元素立刻transfer(传输)给消费者。如果没有消费者在等待接收元素,transfer方法会将元素存放在队列的tail节点,并等到该元素被消费者消费了才返回。
tryTransfer:是用来试探生产者传入的元素是否能直接传给消费者。如果没有消费者等待接收元素,则返回false。和transfer方法的区别是tryTransfer方法无论消费者是否接收,方法立即返回,而transfer方法是必须等到消费者消费了才返回。
在这里插入图片描述

2、JAVA并发工具类

2.1、CountDownLatch

允许一个或多个线程等待其他线程完成操作


import java.util.concurrent.CountDownLatch;

public class CountDownLatchTest {
	/*构造函数接收一个int类型的参数作为计数器,如果你想等待N个点完
	成,这里就传入N。
	*/
    static CountDownLatch c = new CountDownLatch(2);
    
    public static void main(String[] args) throws InterruptedException {
        new Thread(new Runnable() {
            @Override
            public void run() {
            	//通过调用countDown()计数减1
                System.out.println(1);
                c.countDown();
                
                System.out.println(2);
                c.countDown();
            }
        }).start();
        
        /* 通过调用CountDownLatch的await方法阻塞线程
		        注:如果某一个线程处理较慢,可以调用await(long time,TimeUnit unit)
		        方法来指定时间不在阻塞当前线程
        */
        c.await();
        
        System.out.println("3");
    }
}

2.2、CyclicBarrier

可循环使用(Cyclic)的屏障(Barrier)。让一组线程到达一个屏障(也可以叫同步点)时被阻塞,直到最后一个线程到达屏障时,屏障才会开门,所有被屏障拦截的线程才会继续运行。

  1. CyclicBarrier(int parties):构造函数指定屏障拦截的线程数。

public class CyclicBarrierTest {
	/*说明:	
	 构造参数表示屏障拦截的线程数量,每个线程调用await方法告诉
	 CyclicBarrier我已经到达了屏障,然后当前线程被阻塞,只有当
	 调用await的线程数与构造参数一致时,线程才会被唤醒,但是线
	 程执行的顺序、是没有保障的,下面输出可以1和2,也可以是2和1	
	*/
    static CyclicBarrier c = new CyclicBarrier(2);
    
    public static void main(String[] args) {
        new Thread(new Runnable() {
            @Override
            public void run() {
                try {
                    c.await();
                } catch (Exception e) {
                }
                System.out.println(1);
            }
        }).start();
        try {
            c.await();
        } catch (Exception e) {
        }
        
        System.out.println(2);
    }
}
  1. CyclicBarrier(int parties,Runnable barrierAction),用于在线程到达屏障时,优先执行barrierAction。

import java.util.concurrent.CyclicBarrier;

public class CyclicBarrierTest {
	/*	
	 构造参数传入的A线程优先执行
	*/
    static CyclicBarrier c = new CyclicBarrier(2, new A());
    
    public static void main(String[] args) {
        new Thread(new Runnable() {
            @Override
            public void run() {
                try {
                    c.await();
                } catch (Exception e) {
                }
                System.out.println(1);
            }
        }).start();
        try {
            c.await();
        } catch (Exception e) {
        }
        
        System.out.println(2);
    }
    
    static class A implements Runnable {
    	@Override
    	public void run() {
    		System.out.println(3);
    	}
    }
}

2.3、CyclicBarrier和CountDownLatch的区别

CountDownLatch的计数器只能使用一次,而CyclicBarrier的计数器可以使用reset()方法重置。所以CyclicBarrier能处理更为复杂的业务场景。例如,如果计算发生错误,可以重置计数器,并让线程重新执行一次。

2.4、Semaphore

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

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

public class SemaphoreTest {
	//总共执行的线程数
    private 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 {
                    //通过acquire方法获得许可
                        s.acquire(); 
                        System.out.println("save data");
                        //使用完释放,后续线程即有获取执行的资格
                        s.release();
                    } catch (InterruptedException e) {
                    }
                }
            });
        }
        
        threadPool.shutdown();
    }
}

2.5、Exchanger

Exchanger(交换者)是一个用于线程间协作的工具类。Exchanger用于进行线程间的数据交换。它提供一个同步点,在这个同步点,两个线程可以交换彼此的数据。这两个线程通过exchange方法交换数据,如果第一个线程先执行exchange()方法,它会一直等待第二个线程也执行exchange方法,当两个线程都到达同步点时,这两个线程就可以交换数据,将本线程生产出来的数据传递给对方。


public class ExchangerTest {
    private static final Exchanger<String> exgr = new Exchanger<String>();
    private static ExecutorService threadPool = Executors.newFixedThreadPool(2);
    public static void main(String[] args) {
        threadPool.execute(new Runnable() {
            @Override
            public void run() {
                try {
                    String A = "银行流水A";   // A录入银行流水数据
                    exgr.exchange(A);
                } catch (InterruptedException e) {
                }
            }
        });
        
        threadPool.execute(new Runnable() {
            @Override
            public void run() {
                try {
                    String B = "银行流水B"; // B录入银行流水数据
                    String A = exgr.exchange("B");
                    System.out.println("A和B数据是否一致:" + A.equals(B) + ",A录入的是:"
                            + A + ",B录入是:" + B);
                } catch (InterruptedException e) {
                }
            }
        });
        threadPool.shutdown();
    }
}

应用场景:
Exchanger 可以用于遗传算法,如需要选出两个人作为交配对象,这时候会交换两人的数据,并使用交叉规则得出2个交配结果。
Exchanger 可以用于校对工作,如银行流水对账。

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值