JDK并发相关并发包

Posted zxx123

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了JDK并发相关并发包相关的知识,希望对你有一定的参考价值。

    synchronized的功能扩展:

    重入锁;ReentrantLock;

        其实也就是lock对于synchronized的替代了,要注意的一个点就是你可以锁多个,但是你锁了几个,最后就要解锁几个这个问题;

        使用lock.lock()加锁,使用lock.unlock()解锁;

    提供中断处理;

  使用中断锁,线程可以被中断,也就是说,当一个线程正在等待锁的时候,他依然可以收到一个通知,被告知无须等待,可以停止工作了,使用的是lock.lockInterruptibly();方法;

    锁申请等待限时;

  给锁给定一个时间,如果超过了这个时间的话,就让线程自动放弃;使用的是lock.trylock(时间段,时间单位);另外还有一个就是lock.trylock();如果是带参数的,就是最多等待这么多时间,超过了时间就返回false,成功获得了锁,就返回true;如果是不带参数直接运行,就是比较直接的,如果锁未被占用,则申请锁成功,返回true,否则就是失败了,直接返回false;

    公平锁;

        公平锁的一个特点就是:它不会产生饥饿现象;所有的锁都是先到先等,不得插队;但是维持公平需要一个有序队列,实现成本较高,性能相对也非常低下,默认情况下,锁是非公平的;

    以下是我们整理的几个重要方法:

        1,lock():获得锁,如果锁已经被占用,则等待;
        2,lockInterruptibly():获得锁,但优先响应中断;
        3,tryLock():尝试获得锁,如果成功,返回true,失败返回false,该方法不等待,立即返回;
        4,tryLock(Long time,TimeUnit unit):在给定的时间内尝试获得锁;
        5,unlock():释放锁;

    重入锁的好搭档:Condition条件;

使用new Condition可以生成与当前重入锁绑定的Condition实例;使得我们可以让线程在合适的时间等待,或者在某一特定的时刻得到通知,继续执行;
        1,await();让当前线程等待,同时释放当前锁,作用上和wait()相似;
        2,awaitUninterruptibly();与await()方法基本相同,不会在等待过程中响应中断;
        3,singal();用于唤醒一个在等待中的线程,相对的singalAll()方法会唤醒所有在等待中的线程,和notify()类似;

    允许多个线程同时访问:信号量;

        只允许一个线程访问一个资源,而信号量则可以指定多个线程;
        public Semaphore(int permits)
        public Semaphore(int permits,boolean fair);第二个参数可以指定是否公平锁;
        这所谓的信号量,其实就是一个执行器啦,只是换了名字看不出来了而已。。。参数可以指定有多少个线程;

    ReadWriteLock读写锁;

关于读写的问题,我们要明确的一点就是,我们可以对一个文件多次重复读取,但是当读与写发生冲突的时候,我们要做的就是保证他们的互斥了;
        读读不互斥;
        读写互斥;
        写写互斥;
    如果读的操作远远大于写的操作的话,读写锁就会发挥最大的功效;
    Lock readLock = readWriteLock.readLock();
    Lock writeLock = readWriteLock.writeLock();
    读线程完全并行,而写会阻塞读;

    倒计时器:CountDownLatch;

        此工具通常用来控制线程等待,让某一个线程等待知道倒计时结束,再开始执行;
        只有当你一开始设定的所有线程都跑完了,你这个倒计时器才算真正结束了;
        CountDownLatch end = new CountDownLatch(10);
        end.countDown();      
        当调用CountDownLatch.countDown()方法的时候,也就是通知CountDownLatch,一个线程已经完成了任务,倒计时器可以减1了;

    循环珊栏;CyclicBarrier;

        另外一种多线程并发控制实用工具;
            其实本质上跟倒计时器是差不多的功能类似,唯一的区别就在于可以反复使用,而且可以设置,当计数结束之后,系统下一步要执行的动作;
        public CyclicBarrier(int parties,Runnable barrierAction);
            其中barrierAction是执行的动作;

    线程阻塞工具类:LockSupport;

        可以在线程内任意位置让线程阻塞;和Thread.suspend()相比,弥补了由于resume()在前发生,导致线程无法继续执行的情况;
        与object.wait()相比,不需要先获得某个对象的锁,也不会抛出interruptedException异常;
        LockSupport.park();
        LockSupport.unpark(t1);
       除了有定时阻塞的功能外,LockSupport.park()还能支持中断影响;但是LockSuppor.park()不会抛出InterruptedException异常,他只是默默的返回; 
        也就是说:LockSupport.park()进行阻塞之后,如果中断这个线程,不会抛出异常,而是默默的返回;

    线程复用:线程池;

        我们在这里用到了池的概念来保存管理我们的线程;
        当我们要使用线程的时候,不是创建,而是从池子中去取,当我们要关闭线程的时候,是将这个线程返回给池子,方便其他人使用;

    JDK对线程池的支持;

         newFixedThreadPool(int nThreads);
         newSingleThreadExecutor();
         newCachedThreadTool();
         newSingleThreadScheduledExector();
         newScheduledThreadPool(int corePoolSize);
    newFixedThreadPool():该方法返回一个固定线程数量的线程池;线程池的数量保持不变,若线程池已满,新的任务会被暂存在一个任务队列中;
    newSingleThreadExecutor();该线程池只有一个线程在里面,多余任务会被保存到一个任务队列中;
    newCachedThreadPool();返回一个根据实际情况调整线程数量的线程池,也就是说,这个线程池中的线程是可以可调整的。当所有的线程都在工作而此时又有新的任务提交,则会扩展线程的数量;
    newSingleThreadScheduledExecutor();返回一个ScheduledExecutorService对象,在ExecutorService接口上扩展了在给定时间执行某任务的功能,
    newScheduledThreadPool()方法,可以指定线程数量和时间的线程池;

    核心线程池的内部实现;

        都是在原有的ThreadPoolExecutor()的基础上进行的参数设置和修改;
        而其实,这个ThreadPoolExecutor()内部的参数也有很多的;
        int corePoolSize;线程池中线程的数量;
        int maximumPoolSize;指定了线程池的最大线程数量;
        long keepAliveTime;当线程池数量超过了corePoolSize时吗,多与的空闲线程的存活时间;
        TimeUnit unit;keepAliveTime的时间单位;
        BlockingQueue<Runnable> workQueue:任务队列,被提交但尚未被执行的任务;
        ThreadFactory threadFactory;线程工厂,用于创建线程,一般用默认的;
        handler;拒绝策略,当任务太多来不及处理,如何拒绝任务;
    现在我们上面的几个线程池是如何通过ThreadPoolExecutor()以及内部的参数来设定的呢,我们现在就来说一下;
        其中newFixedThreadPool(nThreads,nThreads,0L,new LinkedBlockingQueue<Runnable>);
        newSingleThreadExecutor(1,1,0L,new LinkedBlockingQueue<Runnable>);
        newCachedThreadPool(0,Integer.MAX_VALUE,60L,TimeUnit.SECONDS,new SynchronousQueue<Runnable>());
        其中,我们可以看出,当newCachedThreadPool时,我们是指定线程池数量为0,但是最大线程数为无限,而且采用的任务队列跟上面的队列不一样,下面将重点说明这两种任务队列的不同之处;
        SynchronousQueue:这是直接提交的队列,每一个线程都会直接提交,不会真实地保存,而是直接将新任务交给线程执行器;
        ArrayBlockingQueue:这是有界的任务队列,需要带一个参数,表示该队列的最大容量;
        LinkedBlockingQueue:这是无界的任务队列,多余的任务会先放到这里;
        PriorityBlockingQueue:这是优先任务队列,根据任务自身的优先级顺序先后执行;

        不要重复发明轮子:JDK的并发容器;

            ConcurrentHashMap:高效的并发HashMap;
            CopyOnWriteArrayList:在读多写少的场合,这个List的性能非常好,远远好于Vector(另外。。Vector已经过时了,不用了);
            ConcurrentLinkedQueue:高效的并发队列,使用链表实现,可以看做一个线程安全的LinkedList;
            BlockingQueue:表示阻塞队列,详情可以查看一下生产者——消费者模式;
            ConcurrentSkipListMap:跳表的实现;这是一个Map,使用跳表的数据结构进行快速查找;
        以上并发容器的内部数据结构实现,我们在下一章会提到;敬请期待!

 


以上是关于JDK并发相关并发包的主要内容,如果未能解决你的问题,请参考以下文章

Java高并发--------JDK并发包-------3

Java高并发--------JDK并发包-------3

Java 并发编程实践基础 读书笔记: 第三章 使用 JDK 并发包构建程序

JAVA高并发程序设计学习-JDK并发包:同步控制一

Java并发之CountDownLatch的使用

3.java并发包