JUC工具包(二)Exchanger和Semaphore

java.util.concurrent 工具包的使用(二)


Exchanger ( 交换器 )

-----作用-----

​ java.util.concurrent包中的Exchanger类可用于两个线程之间交换信息。可简单地将Exchanger对象理解为一个包含两个格子的容器,通过exchanger方法可以向两个格子中填充信息。当两个格子中的均被填充时,该对象会自动将两个格子的信息交换,然后返回给线程,从而实现两个线程的信息交换。


-----构造函数-----
构造函数作用备注
public Exchanger()构造一个Exchanger对象

-----常用API-----
API作用备注
public V exchange(V x) throws InterruptedException等待与另外的线程交换一个对象是个阻塞方法,可,可中断
public V exchange(V x, long timeout, TimeUnit unit)用第一个,有时间限制,会超时再2个线程交换的时候,如果一个线程提前结束,可能会导致另外一个线程死等待

-----代码示例-----
  1. Example 1 最简单的交换 Demo

    package myConcurrent.s2020_03_27;
    
    import java.util.concurrent.Exchanger;
    
    public class ExchangerExample1 {
        public static void main(String[] args) {
            final Exchanger<String> exchanger = new Exchanger<>();
    
            new Thread(() -> {
                try {
                    String call = "我是AAAA的消息";
                    System.out.println(Thread.currentThread().getName() + " 发送了 >>> " + call);
                    String str = exchanger.exchange(call);
                    System.out.println(Thread.currentThread().getName() + " 收到了 >>> " + str);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            },"AAAAAA").start();
    
            new Thread(() -> {
                try {
                    String call = "我是BBBB的消息";
                    System.out.println(Thread.currentThread().getName() + " 发送了 >>> " + call);
                    String str = exchanger.exchange(call);
                    System.out.println(Thread.currentThread().getName() + " 收到了 >>> " + str);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            },"BBBBB").start();
    
        }
    }
    
    
  2. Example 2测试有时间限制的方法 (注意 一旦一个设置了 超时延迟,要把另一个也要设,否则会有死等待的可能 )

    package myConcurrent.s2020_03_27;
    
    import java.util.concurrent.Exchanger;
    import java.util.concurrent.TimeUnit;
    import java.util.concurrent.TimeoutException;
    
    /**
     * 有时间限制
     * */
    public class ExchangerExample2 {
        public static void main(String[] args) throws InterruptedException {
            final Exchanger<String> exchanger = new Exchanger<>();
    
            new Thread(() -> {
                try {
                    String str = exchanger.exchange("ssdf",1, TimeUnit.SECONDS);
                    System.out.println(str);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                } catch (TimeoutException e) {
                    System.out.println("超时了!");
                    e.printStackTrace();
                }
            }).start();
    
            TimeUnit.SECONDS.sleep(2);
            
            new Thread(() -> {
                try {
                    String str = exchanger.exchange("ssdf",1, TimeUnit.SECONDS);
                    System.out.println(str);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                } catch (TimeoutException e) {
                    System.out.println("超时了!");
                    e.printStackTrace();
                }
            }).start();
        }
    }
    
  3. 由于交换,涉及了对象的发布,可能会导致一些线程安全的问题,因此对象的交换要和原子引用结合在一起

    package myConcurrent.s2020_03_27;
    
    import java.util.concurrent.Exchanger;
    import java.util.concurrent.TimeUnit;
    import java.util.concurrent.atomic.AtomicReference;
    
    public class ExchangerExample3 {
        public static void main(String[] args) throws InterruptedException {
            final Exchanger<UnSafeObject> exchanger = new Exchanger<>();
            new Thread(() -> {
                UnSafeObject adf = new UnSafeObject("adf", 12);
    
                AtomicReference<UnSafeObject> reference = new AtomicReference<>(adf);
                try {
                    UnSafeObject exchange = exchanger.exchange(reference.get());
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }).start();
    
            TimeUnit.SECONDS.sleep(1);
    
            new Thread(() -> {
                UnSafeObject object = new UnSafeObject("abc",1);
    
                AtomicReference<UnSafeObject> reference = new AtomicReference<>(object);
                try {
                    UnSafeObject exchange = exchanger.exchange(reference.get());
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }).start();
        }
    
        static class UnSafeObject {
            private String name;
            private int age;
    
            public void setName(String name) {
                this.name = name;
            }
    
            public void setAge(int age) {
                this.age = age;
            }
    
            public UnSafeObject(String name, int age) {
                this.name = name;
                this.age = age;
            }
    
            public String getName() {
                return name;
            }
    
            public int getAge() {
                return age;
            }
        }
    }
    
    



Semaphore ( 信号量 )

-----作用-----
  • 它是一个计数信号量
  • 一个更贴切的称呼----许可证管理器
  • 拥有这一组许可证

-----构造函数-----
构造函数作用备注
public Semaphore(int permits)构造一个拥有permits个的许可证的管理器permits并没有做什么限制,负数也是可以的
public Semaphore(int permits, boolean fair)同一,另一个参数是 是否 公平,如果是公平,尽量会使每个线程得到相同的抢占数量使用第一种构造,默认是不公平的

-----常用API-----
API作用备注
public void acquire() throws InterruptedException向管理器要一个许可证,如果没有了,就会陷入阻塞
public void acquire(int permits) throws InterruptedException作用和第一个方法一样,就是向管理器要permits个许可证
public void acquireUninterruptibly()作用和第一个方法一样,但是不会响应中断信号
public void acquireUninterruptibly(int permits)同第3个方法,申请的数量不同
public boolean tryAcquire()尝试向管理器要一个许可证,如果没有,就不要了.不会陷入阻塞,一种尝试
public boolean tryAcquire(int permits)尝试向管理器要permits个许可证,如果没有,就不要了
public boolean tryAcquire(long timeout, TimeUnit unit) throws InterruptedException尝试一段时间向管理器要一个许可证,如果没有,就不要了,会有短暂的阻塞(能够响应中断)返回值就是有没有抢到
public boolean tryAcquire(int permits, long timeout, TimeUnit unit) throws InterruptedException同上
public void release()向管理器归还一个许可证
public void release(int permits)向管理器归还permits个许可证permits小于0会报错
public int availablePermits()精确的获得当前管理器还有多少个许可证可以用来实时监控这个管理器
public int drainPermits()获取当前管理器的所有许可证返回值是获得了多少个许可证
public final int getQueueLength()获得正在等待获取许可证的线程数量这是个估计值,不是十分精确,可是用来监控管理器用的方法

-----代码示例-----
  1. Example 1 测试了基本的使用 以及 一个 监控 管理器的实现

    package myConcurrent.s2020_03_27;
    
    import java.util.concurrent.Semaphore;
    import java.util.concurrent.TimeUnit;
    import java.util.stream.IntStream;
    
    public class SemaphoreExample1 {
        public static void main(String[] args) throws InterruptedException {
            final Semaphore semaphore = new Semaphore(-1);
            //获取许可证超过时间的例子
            boolean flag = semaphore.tryAcquire(2, TimeUnit.SECONDS);
            System.out.println("是否获得了许可证 : " + flag);
    
            //给管理器补充一些许可证
            semaphore.release(11);
    
            //现在拥有10个许可证
            System.out.println("现在拥有个 " + semaphore.availablePermits() + " 可用的许可证");
    
            IntStream.range(0, 100).forEach(i -> {
                new Thread(() -> {
                    try {
                        semaphore.acquire();
                        Thread.sleep(1000);
                        System.out.println(i + "完成了工作!--");
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    } finally {
                        semaphore.release();    //归还许可证
                    }
                }).start();
            });
    
            Thread monitor = new Thread(() -> {
                while (true){
                    int queueLength = semaphore.getQueueLength();
                    int number = semaphore.availablePermits();
                    System.out.println("==================================\n" +
                            "当前有" + queueLength + "个线程正在等待获取许可证\n" +
                            "当前有" + number + "个可用的许可证\n" +
                            "==============================");
                    try {
                        Thread.sleep(1_000);
                    } catch (InterruptedException ignore) {
                        break;
                    }
                }
            });
    
            monitor.start();
    
            Thread.sleep(20_000);
            monitor.interrupt();
        }
    }
    



感谢观看

记录萌新的学习经历

欢迎大佬来拍砖

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值