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 + "比赛结束!");  

    }  

}

 

 

 

本教程由尚硅谷教育大数据研究院出品,如需转载请注明来源,欢迎大家关注尚硅谷公众号(atguigu)了解更多。