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高并发程序设计》的读书笔记

  • 相关阅读:
    at org.apache.catalina.loader.WebappClassLoader.loadClass问题处理
    java ee 中文乱码的问题
    java.lang.IllegalStateException: getWriter() has already been called for this response问题解决
    Project Euler Problem 23 Non-abundant sums
    Project Euler Problem 24 Lexicographic permutations
    Project Euler Problem 19 Counting Sundays
    CCF201703-2 学生排队(100分)
    Project Euler Problem 17 Number letter counts
    CCF201703-1 分蛋糕(100分)
    Project Euler Problem 92 Square digit chains
  • 原文地址:https://www.cnblogs.com/chentingk/p/8540823.html
Copyright © 2011-2022 走看看