java.util.concurrent和工具类

三、Semaphor信号量

信号量可以干什么呢?根据一些阀值做访问控制。我们这里模拟一个当多个线程并发一段代码的时候,如何控制其访问速度

import java.util.Random; 

import java.util.concurrent.Semaphore; 

 

 

  public class SemaphoreTest { 

      private final static Semaphore MAX_SEMA_PHORE = new Semaphore(10); 

      public static void main(String []args) { 

           for(int i = 0 ; i < 100 ; i++) { 

                final int num = i; 

                final Random radom = new Random(); 

                new Thread() { 

                     public void run() { 

                         boolean acquired = false; 

                         try { 

                              MAX_SEMA_PHORE.acquire(); 

                              acquired = true; 

                              System.out.println("我是线程:" + num + " 我获得了使用权!" + DateTimeUtil.getDateTime()); 

                              long time = 1000 * Math.max(1, Math.abs(radom.nextInt() % 10)); 

                              Thread.sleep(time); 

                              System.out.println("我是线程:" + num + " 我执行完了!" + DateTimeUtil.getDateTime()); 

                         }catch(Exception e) { 

                              e.printStackTrace(); 

                         }finally { 

                              if(acquired) { 

                                 MAX_SEMA_PHORE.release(); 

                              } 

                         } 

                      } 

                }.start(); 

           } 

      } 

  }

 

上述是简单模拟并发100个线程去访问一段程序,此时要控制最多同时运行的是10个,用到了这个信号量,运行程序用了一个线程睡眠一个随机的时间来代替,你可以看到后面有线程说自己释放了,就有线程获得了,没释放是获取不到的

 

四、Exchanger线程交互

用于线程之间交互数据,且在并发时候使用,两两交换,交换中不会因为线程多而混乱,发送出去没接收到会一直等,由交互器完成交互过程

 

import java.util.concurrent.Exchanger; 

 

public class ExchangerTest { 

     

    public static void main(String []args) { 

        final Exchanger <Integer>exchanger = new Exchanger<Integer>(); 

        for(int i = 0 ; i < 10 ; i++) { 

            final Integer num = i; 

            new Thread() { 

                public void run() { 

                    System.out.println("我是线程:Thread_" + this.getName() + "我的数据是:" + num); 

                    try { 

                        Integer exchangeNum = exchanger.exchange(num); 

                        Thread.sleep(1000); 

                        System.out.println("我是线程:Thread_" + this.getName() + "我原先的数据为:" + num + " , 交换后的数据为:" + exchangeNum); 

                    } catch (InterruptedException e) { 

                        e.printStackTrace(); 

                    } 

                } 

            }.start(); 

        } 

    } 

这里运行你可以看到,如果某个线程和另一个线程传送了数据,它接受到的数据必然是另一个线程传递给他的,中间步骤由Exchanger去控制

 

五、CyclicBarrier关卡模式

当你在很多环节需要卡住,要多个线程同时在这里都达到后,再向下走,很有用

假如,团队出去旅行,大家一起先达到酒店住宿,然后一起达到游乐的地方游玩,然后一起坐车回家,每次需要点名后确认相关人员均达到,然后LZ一声令下,触发,大伙就疯子般的出发了

import java.util.concurrent.BrokenBarrierException; 

import java.util.concurrent.CyclicBarrier; 

 

public class BarrierTest { 

     

    private static final int THREAD_COUNT = 10; 

     

    private final static CyclicBarrier CYCLIC_BARRIER = new CyclicBarrier(THREAD_COUNT  , 

        new Runnable() { 

            public void run() { 

                System.out.println("======>我是导游,本次点名结束,准备走下一个环节!"); 

            } 

        } 

    ); 

     

    public static void main(String []args)  

            throws InterruptedException, BrokenBarrierException { 

        for(int i = 0 ; i < 10 ; i++) { 

            new Thread(String.valueOf(i)) { 

                public void run() { 

                    try { 

                        System.out.println("我是线程:" + this.getName() + " 我们达到旅游地点!"); 

                        CYCLIC_BARRIER.await(); 

                        System.out.println("我是线程:" + this.getName() + " 我开始骑车!"); 

                        CYCLIC_BARRIER.await(); 

                        System.out.println("我是线程:" + this.getName() + " 我们开始爬山!"); 

                        CYCLIC_BARRIER.await(); 

                        System.out.println("我是线程:" + this.getName() + " 我们回宾馆休息!"); 

                        CYCLIC_BARRIER.await(); 

                        System.out.println("我是线程:" + this.getName() + " 我们开始乘车回家!"); 

                        CYCLIC_BARRIER.await(); 

                        System.out.println("我是线程:" + this.getName() + " 我们到家了!"); 

                    } catch (InterruptedException e) { 

                        e.printStackTrace(); 

                    } catch (BrokenBarrierException e) { 

                        e.printStackTrace();  

                    } 

                } 

            }.start(); 

        } 

    } 

}

测试结果中可以发现,大家一起走到某个步骤后,导游说:“我是导游,本次点名结束,准备走下一个环节!”,然后才会进入下一个步骤,OK,这个有点意思吧,其实赛马也是这个道理,只是赛马通常只有一个步骤,所以我们还有一个方式是:

 

六、CountDownLatch计数器

CountDownLatch的方式来完成赛马操作,CountDownLatch是用计数器来做的,所以它不可以被复用,如果要多次使用,就要从新new一个出来才可以。我们下面的代码中,用两组赛马,每组5个参与者来,做一个简单测试

import java.util.concurrent.CountDownLatch; 

 

public class CountDownLatchTest { 

     

    private final static int GROUP_SIZE = 5; 

     

    public static void main(String []args) { 

        processOneGroup("分组1"); 

        processOneGroup("分组2"); 

    } 

     

    private static void processOneGroup(final String groupName) { 

        final CountDownLatch start_count_down = new CountDownLatch(1); 

        final CountDownLatch end_count_down = new CountDownLatch(GROUP_SIZE); 

        System.out.println("==========================>\n分组:" + groupName + "比赛开始:"); 

        for(int i = 0 ; i < GROUP_SIZE ; i++) { 

            new Thread(String.valueOf(i)) { 

                public void run() { 

                    System.out.println("我是线程组:【" + groupName + "】,第:" + this.getName() + " 号线程,我已经准备就绪!"); 

                    try { 

                        start_count_down.await();//等待开始指令发出即:start_count_down.countDown(); 

                    } catch (InterruptedException e) { 

                        e.printStackTrace(); 

                    } 

                    System.out.println("我是线程组:【" + groupName + "】,第:" + this.getName() + " 号线程,我已执行完成!"); 

                    end_count_down.countDown(); 

                } 

            }.start(); 

        } 

        try { 

            Thread.sleep(1000); 

        } catch (InterruptedException e) { 

            e.printStackTrace(); 

        } 

        System.out.println("各就各位,预备!"); 

        start_count_down.countDown();//开始赛跑 

        try { 

            end_count_down.await();//等待多个赛跑者逐个结束 

        } catch (InterruptedException e) { 

            e.printStackTrace(); 

        } 

        System.out.println("分组:" + groupName + "比赛结束!"); 

    } 

}

 

 

本教程由尚硅谷教育大数据研究院出品,如需转载请注明来源。

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值