• Java同步工具类总结


    先谈谈闭锁和栅栏的区别:

    1.关键区别在于,所有线程必须同时到达栅栏位置,才能继续执行。

    2.闭锁用于等待某一个事件的发生,举例:CountDownLatch中await方法等待计数器为零时,所有事件才可继续执行。而栅栏是等待其他线程到位,所有事件才可继续下一步。例如:几个家庭决定在某个地方集合:“所有人6:00在麦当劳碰头,到了以后要等其他人,之后再讨论下一步要做的事情”。

    Semaphore(闭锁)

    这个东西和之前的synchronized干的事差不多。
    synchronized保证了,我管理的那部分代码同一时刻只有一个线程能访问
    Semaphore保证了,我管理的那部分代码同一时刻最多可以有n个线程访问

    import java.util.concurrent.ExecutorService;  
    import java.util.concurrent.Executors;  
    import java.util.concurrent.Semaphore;  
      
      
    public class SemaphoreTest {  
        public static void main(String[] args) {  
            ExecutorService service = Executors.newCachedThreadPool();  
            final  Semaphore sp = new Semaphore(3);  
            for(int i=0;i<10;i++){  
                Runnable runnable = new Runnable(){  
                        public void run(){  
                        try {  
                            sp.acquire();  
                        } catch (InterruptedException e1) {  
                            e1.printStackTrace();  
                        }  
                        System.out.println("线程" + Thread.currentThread().getName() +   
                                "进入,当前已有" + (3-sp.availablePermits()) + "个并发");  
                        try {  
                            Thread.sleep((long)(Math.random()*10000));  
                        } catch (InterruptedException e) {  
                            e.printStackTrace();  
                        }  
                        System.out.println("线程" + Thread.currentThread().getName() +   
                                "即将离开");                      
                        sp.release();  
                        //下面代码有时候执行不准确,因为其没有和上面的代码合成原子单元  
                        System.out.println("线程" + Thread.currentThread().getName() +   
                                "已离开,当前已有" + (3-sp.availablePermits()) + "个并发");                      
                    }  
                };  
                service.execute(runnable);            
            }  
        }  
      
      
    }  
    

     运行结果如下:

    线程pool-1-thread-2进入,当前已有2个并发
    线程pool-1-thread-1进入,当前已有2个并发
    线程pool-1-thread-3进入,当前已有3个并发
    线程pool-1-thread-1即将离开
    线程pool-1-thread-1已离开,当前已有2个并发
    线程pool-1-thread-4进入,当前已有3个并发
    线程pool-1-thread-3即将离开
    线程pool-1-thread-3已离开,当前已有2个并发
    线程pool-1-thread-5进入,当前已有3个并发
    线程pool-1-thread-2即将离开
    线程pool-1-thread-2已离开,当前已有2个并发
    线程pool-1-thread-6进入,当前已有3个并发
    线程pool-1-thread-4即将离开
    线程pool-1-thread-4已离开,当前已有2个并发
    线程pool-1-thread-7进入,当前已有3个并发
    线程pool-1-thread-5即将离开
    线程pool-1-thread-5已离开,当前已有2个并发
    线程pool-1-thread-8进入,当前已有3个并发
    线程pool-1-thread-8即将离开
    线程pool-1-thread-9进入,当前已有3个并发
    线程pool-1-thread-8已离开,当前已有3个并发
    线程pool-1-thread-6即将离开
    线程pool-1-thread-6已离开,当前已有2个并发
    线程pool-1-thread-10进入,当前已有3个并发
    线程pool-1-thread-10即将离开
    线程pool-1-thread-10已离开,当前已有2个并发
    线程pool-1-thread-7即将离开
    线程pool-1-thread-7已离开,当前已有1个并发
    线程pool-1-thread-9即将离开
    线程pool-1-thread-9已离开,当前已有0个并发
    

     参考链接:http://www.cnblogs.com/nullzx/archive/2016/03/12/5270233.html 

    CountDownLatch (闭锁)

    它保证了什么功能呢?其实和CycliBarrier也类似。

    看下面这个图

    这就是CycleBarrier,线程自己管理自己,大家看到人都到齐了,才继续走。


    这个是CountDownLatch,由他人来协调进度。

    例如跑步的时候,有个裁判,等所有的人都到齐了,他吹哨,然后大家开始跑,等所有人都跑完了,他才公布成绩。

    import java.util.concurrent.CountDownLatch;  
    import java.util.concurrent.ExecutorService;  
    import java.util.concurrent.Executors;  
      
      
    public class CountdownLatchTest {  
      
      
        public static void main(String[] args) {  
            ExecutorService service = Executors.newCachedThreadPool();  
            final CountDownLatch cdOrder = new CountDownLatch(1);  
            final CountDownLatch cdAnswer = new CountDownLatch(3);        
            for(int i=0;i<3;i++){  
                Runnable runnable = new Runnable(){  
                        public void run(){  
                        try {  
                            System.out.println("线程" + Thread.currentThread().getName() +   
                                    "正准备接受命令");                       
                            cdOrder.await();  
                            System.out.println("线程" + Thread.currentThread().getName() +   
                            "已接受命令");                                 
                            Thread.sleep((long)(Math.random()*10000));    
                            System.out.println("线程" + Thread.currentThread().getName() +   
                                    "回应命令处理结果");                          
                            cdAnswer.countDown();                         
                        } catch (Exception e) {  
                            e.printStackTrace();  
                        }                 
                    }  
                };  
                service.execute(runnable);  
            }         
            try {  
                Thread.sleep((long)(Math.random()*10000));  
              
                System.out.println("线程" + Thread.currentThread().getName() +   
                        "即将发布命令");                        
                cdOrder.countDown();  
                System.out.println("线程" + Thread.currentThread().getName() +   
                "已发送命令,正在等待结果");      
                cdAnswer.await();  
                System.out.println("线程" + Thread.currentThread().getName() +   
                "已收到所有响应结果");     
            } catch (Exception e) {  
                e.printStackTrace();  
            }                 
            service.shutdown();  
      
      
        }  
    }  
    

     运行结果如下

    线程pool-1-thread-3正准备接受命令
    线程pool-1-thread-1正准备接受命令
    线程pool-1-thread-2正准备接受命令
    线程main即将发布命令
    线程main已发送命令,正在等待结果
    线程pool-1-thread-3已接受命令
    线程pool-1-thread-2已接受命令
    线程pool-1-thread-1已接受命令
    线程pool-1-thread-3回应命令处理结果
    线程pool-1-thread-1回应命令处理结果
    线程pool-1-thread-2回应命令处理结果
    线程main已收到所有响应结果
    

    CountDownLatch里面有个计数器,初始值就是new countdownlatch时传入的

    wait方法会一直等待,直到计数器的值变为0

    coutdown方法可以让计数器的值减一

    CycleBarrier(栅栏)

    CycleBarrier 能做到让n个线程互相等待,当n个线程都做到某一步后,再继续下一步。

    例如下面的例子,5个人去旅游,设置abc三个中途节点,所有人都到达a之后在继续走向b,所有人都到达b,然后才继续走向c。

    import java.util.concurrent.CyclicBarrier;  
    import java.util.concurrent.ExecutorService;  
    import java.util.concurrent.Executors;  
      
      
    public class CyclicBarrierTest {  
      
      
        public static void main(String[] args) {  
            ExecutorService service = Executors.newCachedThreadPool();  
            final  CyclicBarrier cb = new CyclicBarrier(3);  
            for(int i=0;i<3;i++){  
                Runnable runnable = new Runnable(){  
                        public void run(){  
                        try {  
                            Thread.sleep((long)(Math.random()*10000));    
                            System.out.println("线程" + Thread.currentThread().getName() +   
                                    "即将到达集合地点1,当前已有" + (cb.getNumberWaiting()+1) + "个已经到达," + (cb.getNumberWaiting()==2?"都到齐了,继续走啊":"正在等候"));                         
                            cb.await();  
                              
                            Thread.sleep((long)(Math.random()*10000));    
                            System.out.println("线程" + Thread.currentThread().getName() +   
                                    "即将到达集合地点2,当前已有" + (cb.getNumberWaiting()+1) + "个已经到达," + (cb.getNumberWaiting()==2?"都到齐了,继续走啊":"正在等候"));  
                            cb.await();   
                            Thread.sleep((long)(Math.random()*10000));    
                            System.out.println("线程" + Thread.currentThread().getName() +   
                                    "即将到达集合地点3,当前已有" + (cb.getNumberWaiting() + 1) + "个已经到达," + (cb.getNumberWaiting()==2?"都到齐了,继续走啊":"正在等候"));                       
                            cb.await();                       
                        } catch (Exception e) {  
                            e.printStackTrace();  
                        }                 
                    }  
                };  
                service.execute(runnable);  
            }  
            service.shutdown();  
        }  
    }  
    

    运行结果如下:

    线程pool-1-thread-2即将到达集合地点1,当前已有1个已经到达,正在等候
    线程pool-1-thread-1即将到达集合地点1,当前已有2个已经到达,正在等候
    线程pool-1-thread-3即将到达集合地点1,当前已有3个已经到达,都到齐了,继续走啊
    线程pool-1-thread-1即将到达集合地点2,当前已有1个已经到达,正在等候
    线程pool-1-thread-3即将到达集合地点2,当前已有2个已经到达,正在等候
    线程pool-1-thread-2即将到达集合地点2,当前已有3个已经到达,都到齐了,继续走啊
    线程pool-1-thread-1即将到达集合地点3,当前已有1个已经到达,正在等候
    线程pool-1-thread-2即将到达集合地点3,当前已有2个已经到达,正在等候
    线程pool-1-thread-3即将到达集合地点3,当前已有3个已经到达,都到齐了,继续走啊
    

    Exchange(栅栏)

    A线程有数据1,它需要与B线程的数据2做交换
    B线程有数据2,它需要与A线程的数据1做交换

    那么什么时候交换呢?得等AB都做好准备才行。

    import java.util.concurrent.Exchanger;  
    import java.util.concurrent.ExecutorService;  
    import java.util.concurrent.Executors;  
      
      
    public class ExchangerTest {  
      
      
        public static void main(String[] args) {  
            ExecutorService service = Executors.newCachedThreadPool();  
            final Exchanger<String> exchanger = new Exchanger<String>();  
            service.execute(new Runnable(){  
                public void run() {  
                    try {                 
      
      
                        String data1 = "zxx";  
                        System.out.println("线程" + Thread.currentThread().getName() +   
                        "正在把数据" + data1 +"换出去");  
                        Thread.sleep((long)(Math.random()*10000));  
                        String data2 = (String)exchanger.exchange(data1);  
                        System.out.println("线程" + Thread.currentThread().getName() +   
                        "换回的数据为" + data2);  
                    }catch(Exception e){  
                          
                    }  
                }     
            });  
            service.execute(new Runnable(){  
                public void run() {  
                    try {                 
      
      
                        String data1 = "lhm";  
                        System.out.println("线程" + Thread.currentThread().getName() +   
                        "正在把数据" + data1 +"换出去");  
                        Thread.sleep((long)(Math.random()*10000));                    
                        String data2 = (String)exchanger.exchange(data1);  
                        System.out.println("线程" + Thread.currentThread().getName() +   
                        "换回的数据为" + data2);  
                    }catch(Exception e){  
                          
                    }                 
                }     
            });       
        }  
    }  
    

     运行结果如下:

    线程pool-1-thread-1正在把数据zxx换出去
    线程pool-1-thread-2正在把数据lhm换出去
    线程pool-1-thread-2换回的数据为zxx
    线程pool-1-thread-1换回的数据为lhm
    
  • 相关阅读:
    为cocos2d-x实现安卓输入框。非全屏,无dialog,绑定到lua
    自己动手,丰衣足食。普通键盘实现键盘宏(Windows和Mac版)
    go语言使用protobuf
    go语言使用redis —— redigo
    go语言实现线程池
    go语言实现的目录共享程序
    ss
    BST
    堆排序—最大优先级队列
    STL_Vector
  • 原文地址:https://www.cnblogs.com/cnmenglang/p/6265155.html
Copyright © 2020-2023  润新知