java初入多线程9

ReadWriteLock 多写锁

  1. ReadWriteLock 是JDK5中提供的读写分离锁,读写分离可以有效的帮助减少锁竞争。用来提高系统性能。
    读写锁的访问约束情况
非阻塞 阻塞
堵塞 阻塞
  • 读读 之间不互斥:读读之间不阻塞
  • 读-写互斥:读阻塞写,写也会阻塞读
  • 写- 写 互斥: 写写堵塞。
public class ReadWriteLockDemo {
    private static Lock lock = 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 InterruptedException {
        try {
            lock.lock();
            Thread.sleep(1000);
            return value;
            
        }finally {
            lock.unlock();
        }
    }
    
    public void handleWrite(Lock lock,int index) throws InterruptedException{
        try {
            lock.lock();  //模拟写的操作
            Thread.sleep(1000);
            value=index;
        } finally {
            lock.unlock();
        }
    }
    
    public static void main(String[] args) {
        final ReadWriteLockDemo  demo= new ReadWriteLockDemo();
        Runnable readRunnable =new Runnable() {
            
            public void run() {
                try {
//                  demo.handleRead(readLock);
                    demo.handleRead(lock);
                } catch (Exception e) {
                    e.printStackTrace();
                }
                
            }
        };
        
        Runnable writerRunnable =new Runnable() {
            
            public void run() {
                try {
//                  demo.handleWrite(writeLock, new Random().nextInt());
                    demo.handleWrite(lock, new Random().nextInt());
                } catch (Exception e) {
                    e.printStackTrace();
                }
                
            }
        };
        
        for (int i = 18; i < 20; i++) {
            new Thread(writerRunnable).start();
        }
    }
    
}

  • 在代码中我们使用了两种方式 如果使用读写锁的该程序执行可以在2秒内执行完毕,但是如果是lock锁的没有进行多写分离,那么会在将近20秒的时间内完成。为什么会这么长时间 ,是因为所有的读线程与写线程之间 必须都互相等待 ,导致的。读写分离之后 读读之间不用互相等待 ,大大减少时间。

倒计时器:CountDownLatch

  • CountDownLatch 是一个非常实用的多线程控制工具类。主要是用来控制线程等待,它可以让某一个线程等待到知道倒计时结束再开始执行。代码演示如下:
public class CountDownLatchDemo implements Runnable {

    static final CountDownLatch end = new  CountDownLatch(10);
    static final CountDownLatchDemo  demo = new CountDownLatchDemo();
    
    
    @Override
    public void run() {
        
        try {
            
            //模拟检查任务 
            Thread.sleep(new Random().nextInt(10)*1000);
            System.out.println("check complete");
            end.countDown();
            
        } catch (Exception e) {
            e.printStackTrace();
        }
        
    }

    public static void main(String[] args) throws Exception {
        ExecutorService exec = new  ThreadPoolExecutor(10, 10,
                  0L, TimeUnit.MILLISECONDS,
                    new LinkedBlockingQueue<Runnable>());
        for(int i = 0 ; i < 10 ; i++){
            exec.submit(demo);
        }
        
        //等待检查
        end.await();
        
        // 发射  相当于开始执行任务
        System.out.println("fire");
        
        exec.shutdown();
    }
}

结果图
  • 在上述代码中 计数器数量为10 ,那么就是需要有10个线程完成任务,在CountDownLatch 上的线程才能继续执行。 在代码中我们能看到有个countdown()方法, 就是用来通知CountDownLatch, 如果一个线程完成任务,那么倒计时器就可以减1.。 我们在await 方法,要求主线程等待所有10个检查任务全部完成,那么主线程才会继续执行。
示意图

循环栅栏 :CyclicBarrier

  • 这是一种不同于 CountDOwnLatch 的多线程并发控制工具,但是也可以实现线程间的计数等待。它比CountDownLatch 功能更加强大且复杂。
  • 循环栅栏 意思就是循环,如果我们使用的是其计数器的功能那么如果是20个,等到计数器归0 之后还会凑齐下一批20个线程,再次形成栅栏。代码如下:
public class CyclicBarrierDemo {
        
    
    public static class Soldier implements Runnable{
        private String soldier;
        private final  CyclicBarrier cyclic ;
        
        public Soldier( CyclicBarrier cyclic , String soldier) {
            this.cyclic = cyclic ;
            this.soldier = soldier ;
        }
        
        @Override
        public void run() {
            try {
                //等到所有任务的到来
                cyclic.await() ;
                doWork();
                
                //等待所有任务完成
                cyclic.await();
                
            } catch (Exception e) {
                // TODO: handle exception
            }
            
        
        }
        
        void doWork(){
            try {
                Thread.sleep(Math.abs(new Random().nextInt()%10_000));
                
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
        
    }
    
    public static class BarrierRun implements Runnable {
        boolean flag ;
        int  N ;
        public BarrierRun(boolean flag, int n) {
            this.flag = flag;
            N = n;
        } 
        
        @Override
        public void run() {
            if(flag){
                System.out.println("司令 : 士兵"+ N + "个,任务完成");
            }else{
                System.out.println("司令 : 士兵"+ N + "个,集合完毕");
            }
            
        }
        
        
    }
    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(cyclic, " 士兵 " + i));
            allSoldier[i].start();
        }
        
    }
}
  • 根据代码中,我们可以发现 执行await 方法的时候 可能会抛出异常, 一个是等待异常InterruptedException,这个是方便相应 外部紧急事件,另外一个异常是BrokenBarrierException ,这个表示 CyclicBarrier 已经损坏, 系统没法等到所有线程然后再开始执行,处理是把所有线程中断 。就避免 线程的永久的等待了


    执行结果
  • 整个过程的流程图如下:


    示意图
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 159,716评论 4 364
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,558评论 1 294
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 109,431评论 0 244
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 44,127评论 0 209
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,511评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,692评论 1 222
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,915评论 2 313
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,664评论 0 202
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,412评论 1 246
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,616评论 2 245
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,105评论 1 260
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,424评论 2 254
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,098评论 3 238
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,096评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,869评论 0 197
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,748评论 2 276
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,641评论 2 271

推荐阅读更多精彩内容