深入分析阻塞队列以及原子操作等并发工具

互斥锁:

多个线程中只有一个线程才能持有锁

共享锁:

该锁可被多个线程共有,典型的就是ReentrantReadWriteLock里的读锁,它的读锁是可以被共享的,但是它的写锁确每次只能被独占
互斥锁只允许一个线程访问,共享锁可以被多个线程访问,在读锁中对于提升了效率和性能

有界队列:固定大小的队列

•ArrayBlockingQueue 基于数组实现的阻塞队列
•LinkedBlockingQueue 其实也是有界队列,但是不设置大小时就时Integer.MAX_VALUE,内部是基于链表实现的
•ArrayBlockingQueue 实现简单,表现稳定,添加和删除使用同一个锁,通常性能不如后者
•LinkedBlockingQueue 添加和删除两把锁是分开的,所以竞争会小一些
•SynchronousQueue 比较奇葩,内部容量为零,适用于元素数量少的场景,尤其特别适合做交换数据用,内部使用队列来实现公平性的调度,使用栈来实现非公平的调度,在Java6时替换了原来的锁逻辑,使用CAS代替了

无界队列:没有设置固定大小的队列,可以直接入列,直到溢出

•ConcurrentLinkedQueue 无锁队列,底层使用CAS操作,通常具有较高吞吐量,但是具有读性能的不确定性,弱一致性——不存在如ArrayList等集合类的并发修改异常,通俗的说就是遍历时修改不会抛异常
•PriorityBlockingQueue 具有优先级的阻塞队列
•DelayedQueue 延时队列,使用场景
•缓存:清掉缓存中超时的缓存数据
•任务超时处理
•补充:内部实现其实是采用带时间的优先队列,可重入锁,优化阻塞通知的线程元素leader
•LinkedTransferQueue 简单的说也是进行线程间数据交换的利器,在SynchronousQueue 中就有所体现,并且并发大神 Doug Lea 对其进行了极致的优化,使用15个对象填充,加上本身4字节,总共64字节就可以避免缓存行中的伪共享问题

阻塞队列的概念

一个指定长度的队列,如果队列满了,添加新元素的操作会被阻塞等待,直到有空位为止。同样,当队列为空时候,请求队列元素的操作同样会阻塞等待,直到有可用元

主要优点

BlockingQueue提供了一个正确的,线程安全的实现。开发人员已经实施了这个功能多年,但要正确使用它却非常棘手。现在,运行时已经由并发专家开发,审查和维护了一个实现。
队列的“阻塞”性质有两个好处。首先,在添加元素时,如果队列容量有限,则内存消耗也是有限的。另外,如果队列消费者远远落后于生产者,则生产者自然会受到限制,因为他们必须等待添加元素。从队列中获取元素时,主要优点是简单; 永远等待是微不足道的,正确地等待指定的超时只是稍微复杂一点。

Demo 使用线程池创建一个线程去进行获取ArrayBlockingQueue里面的数据(take如果没有获取到数据会将当前线程阻塞,若有数据进来了则会唤醒)
    public static void main( String[] args ) throws InterruptedException {
        BlockingQueue<String> blockingQueue=new ArrayBlockingQueue<>(10);
        blockingQueue.put("Test");
        blockingQueue.take(); //当队列为空的时候会一直阻塞知道有数据才会进行唤醒 //wait/notify   | condition .await/signal | Lock
//        blockingQueue.iterator();
        System.out.println( "Hello World!" );
    }
private final ExecutorService executorService= Executors.newSingleThreadExecutor();
ArrayBlockingQueue<String> arrayBlockingQueue=new ArrayBlockingQueue(10);
public void init(){ //不断消费队列的线程
        executorService.execute(()->{
            while(true){
                try {
                    String s=arrayBlockingQueue.take(); //阻塞式
                    System.out.println("获取数据:"+ s);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        });
    }
  public boolean test(){
        try {
            arrayBlockingQueue.put("ttt");
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        return true;
    }

CountDownLatch 工具使用,类似于join的功能

可以通过CountDownLatch 去控制线程的结果和等待
运用了AQS的共享锁机制

 private void doAcquireSharedInterruptibly(int arg)
        throws InterruptedException {
        //加入一个双向的队列
        final Node node = addWaiter(Node.SHARED);
        boolean failed = true;
        try {
            for (;;) {
                final Node p = node.predecessor();
                if (p == head) {
                	//抢占共享锁,判断state的值
                    int r = tryAcquireShared(arg);
                    if (r >= 0) {
                    	//设置下一个Node为头节点,并且进行传递唤醒(类似多米诺骨牌)
                        setHeadAndPropagate(node, r);
                        p.next = null; // help GC
                        failed = false;
                        return;
                    }
                }
                if (shouldParkAfterFailedAcquire(p, node) &&
                    parkAndCheckInterrupt())
                    throw new InterruptedException();
            }
        } finally {
            if (failed)
                cancelAcquire(node);
        }
    }
    private void setHeadAndPropagate(Node node, int propagate) {
        Node h = head; // Record old head for check below
        setHead(node);
        //表示当前节点可以往下面进行传递
        if (propagate > 0 || h == null || h.waitStatus < 0 ||
            (h = head) == null || h.waitStatus < 0) {
            Node s = node.next;
            //当为空或者是share状态时
            if (s == null || s.isShared())
            	
                doReleaseShared();
        }
    }
    private void doReleaseShared() {
        for (;;) {
            Node h = head;
            if (h != null && h != tail) {
                int ws = h.waitStatus;
                if (ws == Node.SIGNAL) {
                    if (!compareAndSetWaitStatus(h, Node.SIGNAL, 0))
                        continue;            // loop to recheck cases
                    unparkSuccessor(h);
                }
                else if (ws == 0 &&
                         !compareAndSetWaitStatus(h, 0, Node.PROPAGATE))
                    continue;                // loop on failed CAS
            }
            if (h == head)                   // loop if head changed
                break;
        }
    }

Semaphore (信号灯)

通过停车位理解(若为5个停车位,若以停满则后续的进来也是要等待)类似于一种限流的机制

Demo

public class SemaphoreDemo1 {


    static class Test extends Thread{

        Semaphore semaphore;
        int num;

        public Test(Semaphore semaphore, int num) {
            this.semaphore = semaphore;
            this.num = num;
        }

        @Override
        public void run() {
            try {
                semaphore.acquire();
                System.out.println("第"+num+"线程占用一个令牌");
                Thread.sleep(3000);
                System.out.println("第"+num+"线程释放一个令牌");
                semaphore.release(); //释放令牌
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}

AtomicDemo

public class AtomicDemo1 {

    public static AtomicInteger i = new AtomicInteger();

    public static void inc(){

        try {
            Thread.sleep(1);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        i.getAndIncrement();
    }

    public static void main(String[] args) {
        for (int j = 0; j < 1000 ; j++) {
            new Thread(()->{
                AtomicDemo1.inc();
            }).start();
        }
        try {
            Thread.sleep(4000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("result:"+i.get());
    }
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值