zoukankan      html  css  js  c++  java
  • Concurrent包工具类使用

    一。读写锁

      传统的同步锁就是独占式锁,当线程使用资源时候保持独占,无论读写。当人们发现请求队列(假设)中相邻请求为读-读的时候,阻塞是一种浪费资源的操作。比如公告板,所有路过的人(请求)都是读操作,并没有因为你和他在读的时候对内容造成了改变,所以在模型中,读与读操作不需要阻塞。而读写相邻则需要进行独占式操作了,因为写未完成的时候,信息是不完整的,此时读出来的信息有可能是错误的,所以写必然要保持独占式操作。而在应用程序中,读的频率是写的好几倍,也就是说如果读-读是不阻塞的,那么对性能来说是毋庸置疑的提升。

      Java中存在一种锁,名曰:ReentrantReadWriteLock。他可以实现内存中对资源操作的读写锁,读与读是不阻塞的。

    import java.util.Random;
    import java.util.concurrent.locks.Lock;
    import java.util.concurrent.locks.ReentrantLock;
    import java.util.concurrent.locks.ReentrantReadWriteLock;
    
    /**
     * Created by MacBook on 2018/3/10.
     */
    public class ReadWriteLockDemo {
        private static Lock relock = new ReentrantLock();
        private static ReentrantReadWriteLock readWriteLock = new ReentrantReadWriteLock();
        private static Lock readLock = readWriteLock.readLock();
        private static Lock writeLock = readWriteLock.writeLock();
        private int value;
        public Object handleRead(Lock lock) throws Exception{
            try{
                lock.lock();
                Thread.sleep(1000);
                return value;
            }finally {
                lock.unlock();
            }
        }
        public void handleWrite(Lock lock,int index) throws Exception{
            try{
                lock.lock();
                Thread.sleep(1000);
                value = index;
            }finally {
                lock.unlock();
            }
        }
        public static void main(String[] args){
            ReadWriteLockDemo demo = new ReadWriteLockDemo();
            Runnable readThread = new Runnable() {
                @Override
                public void run() {
                    try{
                        System.out.println("read:"+demo.handleRead(readLock));
                    }catch (Exception e){
                        e.printStackTrace();
                    }
                }
            };
            Runnable writeThread = new Runnable() {
                @Override
                public void run() {
                    try{
    //                    demo.handleWrite(relock,new Random().nextInt());
                        demo.handleWrite(writeLock,new Random().nextInt());
                        System.out.println("id:"+Thread.currentThread().getId()+" done!");
                    }catch (Exception e){
                        e.printStackTrace();
                    }
                }
            };
            for(int i=0;i<18;i++){
                new Thread(readThread).start();
            }
            for(int i=0;i<18;i++){
                new Thread(writeThread).start();
            }
        }
    
    }

        此demo使用了重入锁和读写锁的对比,在主程序中分别新建18个读写操作,如果使用了读操作,则打印的读操作是连续的;如果使用了重入锁,则可能的情况是读写相邻打印,并且都是阻塞的,读者可以自行测试体会。

    二。对象监视器Condition

      在JDK实现了Lock来简化synchronized之后,Condition作为简化监视器而存在。Condition的await方法和signal方法对应对象的wait和signal。

    import java.util.concurrent.locks.Condition;
    import java.util.concurrent.locks.ReentrantLock;
    
    /**
     * Created by MacBook on 2018/3/10.
     */
    public class ConditionAndLock implements Runnable{
        static ReentrantLock lock = new ReentrantLock();
        static Condition condition = lock.newCondition();
    
        public void run(){
            try{
                lock.lock();
                condition.await();
                System.out.println("thread is running");
            }catch (Exception e){
                e.printStackTrace();
            }finally {
                lock.unlock();
            }
        }
        public static void main(String[] args){
            ConditionAndLock c = new ConditionAndLock();
            Thread t = new Thread(c);
            t.start();
            lock.lock();
            System.out.println("signal all");
            condition.signalAll();
            lock.unlock();
        }
    }

    三。倒计时器CountDownLatch

      多线程中,需要知道这批线程的最大完成任务时间,也就是从第一个任务开始到最后返回这段时间的时长,那么倒计时器是必不可少的。就像各项资源准备完毕才进行下一步操作的模型一样,CountDownLatch就是这样的多线程模型。等到所有任务调用了计数器,并且计数器总数到达某个数量时候,它才会将阻塞代码放开,让主线程往下走。

    import java.util.Random;
    import java.util.concurrent.CountDownLatch;
    import java.util.concurrent.Executor;
    import java.util.concurrent.ExecutorService;
    import java.util.concurrent.Executors;
    
    /**
     * 倒计时器
     * Created by MacBook on 2018/3/10.
     */
    public class CountDownLatchDemo implements Runnable{
        static CountDownLatch end = new CountDownLatch(10);
        static CountDownLatchDemo demo = new CountDownLatchDemo();
        public void run(){
            try{
                Thread.sleep(new Random().nextInt(10)*1000);
                System.out.println(Thread.currentThread().getId()+" check complete!");
                end.countDown();
            }catch (Exception e){
                e.printStackTrace();
            }
        }
        public static void main(String[] args) throws Exception{
            ExecutorService service = Executors.newFixedThreadPool(10);
            for(int i=0;i<10;i++){
                service.submit(demo);
            }
            end.await();
            System.out.println("fire");
            service.shutdown();
        }
    }

        await方法是阻塞倒计时器所在线程的方法,等到线程池service中调用countDown方法到达一定的数量(此处是10)之后,主线程的await方法才会过去。

    四。信号量

      信号量这个东西就比较玄乎了,有点像准入许可,拿到信号准入的时候才往下执行。就像是有一批人拿号,只有号码区间在某个范围的人能进去办事,然后办完事就会让资源释放,号码区间往后移。然而在信号量中应该算是复用类型的,归还了key值,将key值返回给下一个申请者。

    import java.util.concurrent.ExecutorService;
    import java.util.concurrent.Executors;
    import java.util.concurrent.Semaphore;
    
    /**
     * Created by MacBook on 2018/3/10.
     */
    public class SemapDemo implements Runnable{
        final Semaphore semp = new Semaphore(5);
        public void run(){
            try{
                semp.acquire();
                Thread.sleep(2000);
                System.out.println(Thread.currentThread().getId()+" done!");
                semp.release();
            }catch (Exception e){
                e.printStackTrace();
            }
        }
        public static void main(String[] args){
            ExecutorService executorService = Executors.newFixedThreadPool(5);
            SemapDemo semapDemo = new SemapDemo();
            for(int i=0;i<20;i++){
                executorService.submit(semapDemo);
            }
            executorService.shutdown();
        }
    }

      在acquire获得key之后,操作读写,之后release。

    五。栅栏

      栅栏和倒计时器很像,就是拦住一堆线程,等到线程数达到某个设定值之后同时把它们放出去。但是不同的是,它可以每次设定值达成时候运行定制线程中的run方法。就像是每次一个栏,够数就放。

    import java.util.Random;
    import java.util.concurrent.CyclicBarrier;
    
    /**
     * Created by MacBook on 2018/3/10.
     */
    public class CylicBarrierDemo {
        public static class Soldier implements Runnable{
            private String soldier;
            private final CyclicBarrier cyclicBarrier;
            Soldier(String soldier,CyclicBarrier cyclicBarrier){
                this.soldier = soldier;
                this.cyclicBarrier = cyclicBarrier;
            }
            public void run(){
                try{
                    cyclicBarrier.await();
                    doWork();
                    cyclicBarrier.await();
                }catch (Exception e){
                    e.printStackTrace();
                }
            }
            public void doWork(){
                try{
                    Thread.sleep(Math.abs(new Random().nextInt()%10000));
                }catch (Exception e){
                    e.printStackTrace();
                }
                System.out.println(soldier + " done!");
            }
        }
        public static class BarrierRun implements Runnable{
            boolean flag;
            int n;
            public BarrierRun(boolean flag,int n){
                this.flag = flag;
                this.n = n;
            }
    
            public void run(){
                if(flag){
                    System.out.println("士兵:"+n+"个 done!");
                }else {
                    System.out.println("士兵:"+n+"个 集合完毕!");
                    flag = true;
                }
            }
        }
        public static void main(String[] args){
            final int n = 10;
            Thread[] allSoldier = new Thread[n];
            boolean flag = false;
            CyclicBarrier cyclic = new CyclicBarrier(n,new BarrierRun(flag,n));
            System.out.println("集合");
            for(int i =0; i < n ; i++){
                System.out.println("士兵 "+i+" 报道");
                allSoldier[i] = new Thread(new Soldier("士兵"+i,cyclic));
                allSoldier[i].start();
            }
        }
    }

      例中CyclicBarrier有两个参数,前一个就是提到的设定值,后一个就是定制线程了。每当到达设定值的时候会触发定制线程。

      每个阶段完成都会调用一下定制线程。

    六。LockSupport提供线程挂起操作的支持类

      正如Condition使得原有的Object监视器封装成了新类,LockSupport提供使线程park和unpark之类的操作。

    import java.util.concurrent.locks.LockSupport;
    
    /**
     * Created by MacBook on 2018/3/10.
     */
    public class LockSupportDemo {
        public static Object u = new Object();
        static ChangeObjectThread t1 = new ChangeObjectThread("t1");
        static ChangeObjectThread t2 = new ChangeObjectThread("t2");
        public static class ChangeObjectThread extends Thread{
            public ChangeObjectThread(String name){
                super.setName(name);
            }
            public void run(){
                synchronized (u){
                    System.out.println("in "+getName());
                    LockSupport.park();
                }
            }
        }
        public static void main(String[] args) throws Exception{
            t1.start();
            Thread.sleep(100);
            t2.start();
            LockSupport.unpark(t1);
            LockSupport.unpark(t2);
            t1.join();
            t2.join();
        }
    
    }

      它在park时候线程会变成wait状态,而不是runnable。

      来自《Java高并发程序设计》的读书笔记

  • 相关阅读:
    ArrayList用法
    MessageBox
    将文本文件导入Sql数据库
    在桌面和菜单中添加快捷方式
    泡沫排序
    Making use of localized variables in javascript.
    Remove double empty lines in Visual Studio 2012
    Using Operations Manager Connectors
    Clear SharePoint Designer cache
    Programmatically set navigation settings in SharePoint 2013
  • 原文地址:https://www.cnblogs.com/chentingk/p/8540823.html
Copyright © 2011-2022 走看看