在Junit测试中利用Concurrent包下相关类实现线程同步

在安卓test包下进行网络请求,会出现子线程中网络请求结果无法输出打印的问题。为解决此问题,考虑利用java多线程并发包下相关类实现线程同步。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

在安卓test包下进行网络请求时,会遇到子线程中网络请求结果无法输出打印的问题,于是想到利用java多线程并发包下相关类来实现线程同步,特此记录。

 

@RunWith(BlockJUnit4ClassRunner.class)
public class ThreadUnitTest {
    private ReentrantLock lock;
    private Semaphore semaphore;
    /*
     * countDownLatch数量不为0时,调用await会阻塞线程,countDown方法使数量减1
     */
    private CountDownLatch countDownLatch;
    /**
     *  一个同步辅助类,它允许一组线程互相等待,直到到达某个公共屏障点 (common barrier point)。
     *  公共屏障点--即初始化时给定的数值大小,
     *  cyclicBarrier 可以用 reset 方法重置等待的线程
     */
    private CyclicBarrier cyclicBarrier;


    /**
     * 在每一个测试方法调用之前执行
     */
    @Before
    public void before(){
        /**
         * lock 和 synchronized主要都是对资源的保护,可以实现在一个时间点,
         * 一个资源或操作,只被一条线程读写或执行。
         * semaphore主要能实现限制线程执行的数量
         * CountDownLatch和CyclicBarrier能实现一组线程等待或同时执行
         */
        semaphore = new Semaphore(1);
        lock = new ReentrantLock();
        countDownLatch = new CountDownLatch(1);   //主线程等待,子线程执行完成后释放数量
        cyclicBarrier = new CyclicBarrier(2);  //主线程和网络请求子线程两个线程
    }

    class SemaphoreRunnable implements Runnable{
        int index;
        public SemaphoreRunnable(int i){
            index = i;
        }

        @Override
        public void run() {
            String threadName = Thread.currentThread().getName();
            try {
                System.out.println(String.format("当前线程%s,剩余信号量:%d",
                        threadName,semaphore.availablePermits()));
                semaphore.acquire();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println(String.format("当前线程%s,剩余信号量:%d",
                    threadName,semaphore.availablePermits()));
            /**
             * 如果注释该行,由于信号量总数为1,前面acquire后数量减1,剩余的数量为0,
             * 导致所有线程都被阻塞,无法继续执行
            */
            semaphore.release();
            if(index == 24){
                countDownLatch.countDown();
            }
        }
    }



    Runnable loginRunnable = new Runnable() {
        @Override
        public void run() {
            String username = "xxxxxxxxx";
            String password = "123456";
            //构造用户登录json对象
            final UserLoginPostBean postBean = new UserLoginPostBean();
            postBean.setLoginName(username);
            postBean.setPassword(password);

            HttpRequestFactory.post(postBean,"suburl",
                    new ResultCallback<String>() {
                @Override
                public void onError(Call<String> request, Throwable e) {
                    synchronized (ThreadUnitTest.class) {
                        ThreadUnitTest.class.notify();
                    }
                    //该方法会让countDownLatch数量减1
                    countDownLatch.countDown();
                    try {
                        cyclicBarrier.await();
                    } catch (BrokenBarrierException e1) {
                        e1.printStackTrace();
                    } catch (InterruptedException e1) {
                        e1.printStackTrace();
                    }
                }

                @Override
                public void onResponse(String response) {
                    //唤醒其它等待的线程
                    synchronized (ThreadUnitTest.class) {
                        ThreadUnitTest.class.notify();
                    }
                    //该方法会让countDownLatch数量减1
                    countDownLatch.countDown();
                    try {
                        cyclicBarrier.await();
                    } catch (BrokenBarrierException e1) {
                        e1.printStackTrace();
                    } catch (InterruptedException e1) {
                        e1.printStackTrace();
                    }
                }
            });
        }
    };


    @Test
    public void testWaitAndNotify() {
        ExecutorService threadPool = Executors.newSingleThreadExecutor();
        threadPool.execute(loginRunnable);
        try {
            //让主线程进入阻塞,待网络请求子线程完成请求后会被唤醒
            synchronized (ThreadUnitTest.class) {
                ThreadUnitTest.class.wait();
            }
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("方法结束,我最后执行");
    }


    @Test
    public void testSemaphore(){
        ExecutorService threadPool = Executors.newFixedThreadPool(10);
        for(int i=0;i<25;i++) {
            SemaphoreRunnable sr = new SemaphoreRunnable(i);
            threadPool.execute(sr);
        }
        try {
            countDownLatch.await();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("方法结束,我最后执行");
    }


    @Test
    public void testCountDownLatch(){
        ExecutorService threadPool = Executors.newSingleThreadExecutor();
        threadPool.execute(loginRunnable);
        try {
            //countDownLatch 的 await方法会阻塞线程一直到 countDownLatch数量为0
            countDownLatch.await();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        System.out.println("方法结束,我最后执行");
    }


    @Test
    public void testCountDownLatch2(){
        // 开始的倒数锁
        final CountDownLatch begin = new CountDownLatch(1);
        // 结束的倒数锁
        final CountDownLatch end = new CountDownLatch(10);
        // 十名选手
        final ExecutorService exec = Executors.newFixedThreadPool(10);
        for (int index = 0; index < 10; index++) {
            final int NO = index + 1;
            Runnable run = new Runnable() {
                public void run() {
                    try {
                        begin.await();// 一直阻塞
                        Thread.sleep((long) (Math.random() * 10000));
                        System.out.println("No." + NO + " arrived");
                    } catch (InterruptedException e) {
                    } finally {
                        end.countDown();
                    }
                }
            };
            exec.submit(run);
        }
        System.out.println("Game Start");
        begin.countDown();
        try {
            end.await();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("Game Over");
        exec.shutdown();
    }




    @Test
    public void testCyclicBarrier(){
        ExecutorService threadPool = Executors.newSingleThreadExecutor();
        threadPool.execute(loginRunnable);
        try {
            /**
             * cyclicBarrier 的 await方法会阻塞线程一直到调用 await方法的
             * 线程数量达到初始化时给定的数量为止
             */
            System.out.println(String.format("正在等待的线程数:%d",
                    cyclicBarrier.getParties()));
            cyclicBarrier.await();  //这里调用加上上面执行runnable里的调用,刚好两次,线程结束阻塞
            cyclicBarrier.reset();  //重置了后,又可以阻塞两条线程
        } catch (BrokenBarrierException e) {
            e.printStackTrace();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        try {
            System.out.println("我要休眠五秒。。。。");
            Thread.sleep(5000);   //休眠两秒,
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        new Thread(new Runnable() {   //又开启一个子线程来调用await结束阻塞
            @Override
            public void run() {
                try {
                    cyclicBarrier.await();
                } catch (BrokenBarrierException e) {
                    e.printStackTrace();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }).start();

        try {
            cyclicBarrier.await();  //调用该方法后,主线程被阻塞
        } catch (BrokenBarrierException e) {
            e.printStackTrace();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("方法结束,我最后执行");
    }



    private static int[] timeWalk = { 5, 8, 15, 15, 10 };
    // 自驾游
    private static int[] timeSelf = { 1, 3, 4, 4, 5 };
    // 旅游大巴
    private static int[] timeBus = { 2, 4, 6, 6, 7 };

    /**
     * CyclicBarrier最重要的属性就是参与者个数,另外最要方法是await()。
     * 当所有线程都调用了await()后,就表示这些线程都可以继续执行,否则就会等待。
     */
    @Test
    public void testCyclicBarrier2(){
        // 三个旅行团
        CyclicBarrier barrier = new CyclicBarrier(4);
        ExecutorService exec = Executors.newFixedThreadPool(3);
        exec.submit(new Tour(barrier, "WalkTour", timeWalk));
        exec.submit(new Tour(barrier, "SelfTour", timeSelf));
        // 当我们把下面的这段代码注释后,会发现,程序阻塞了,无法继续运行下去。
        exec.submit(new Tour(barrier, "BusTour", timeBus));

        try {
            barrier.await();
        } catch (BrokenBarrierException e) {
            e.printStackTrace();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        exec.shutdown();
    }



    @Test
    public void testReentrantLock() {
        ExecutorService service = Executors.newCachedThreadPool();
        TestReentrantLock lock = new TestReentrantLock();
        for (int i = 0; i < 10; i++) {
            service.submit(new MyReentrantLock(i, lock));
        }
        service.shutdown();
    }

    @Test
    public void testFuture(){
        final ExecutorService exe=Executors.newFixedThreadPool(3);
        Callable<String> call=new Callable<String>(){
            public String call() throws InterruptedException {
                return "Thread is finished";
            }
        };
        Future<String> task=exe.submit(call);
        String obj= null;
        try {
            obj = task.get();
        } catch (ExecutionException e) {
            e.printStackTrace();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println(obj+"进程结束");
        System.out.println("总进程结束");
        exe.shutdown();

    }



}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值