Java并发编程(二)

本文深入讲解了Java中四种常用的并发控制工具:CountDownLatch、Semaphore、CyclicBarrier和ReentrantLock。通过实例代码演示了每种工具的具体应用及注意事项。

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

CountDownLatch

这里写图片描述
解释一下这张图
新建一个coundDownLatch,值为3
线程A调用coundDownLatch的await方法,线程将被阻塞
线程1执行的实现调用coundDownLatch.countDown方法,则coundDownLatch的值减一,变成2
知道coundDownLatch的值为0,线程A恢复运行

public class CountDownLatchTest {

    private final static int threadCount = 200;

    public static void main(String[] args) throws InterruptedException {
        ExecutorService pool = Executors.newCachedThreadPool();
        //新建一个CountDownLatch 
        final CountDownLatch cdl = new CountDownLatch(threadCount);
        for(int i = 0; i < threadCount; ++i) {
            final int threadNum = i;
            pool.execute(new Runnable() {

                @Override
                public void run() {
                    System.out.println(threadNum);
                    //对每个线程进行减一操作
                    cdl.countDown();
                }
            });
        }
        //此处await也可以添加参数,表示等待的时间
        cdl.await();
        pool.shutdown();
        System.out.println("end");
    }
}

Semaphore

相当于一个信号量,用来控制同一时间多少线程并发执行

private final static int threadCount = 200;

public static void main(String[] args) throws InterruptedException {

    final Semaphore seam = new Semaphore(3);

    ExecutorService pool = Executors.newCachedThreadPool();
    for(int i = 0; i < threadCount; ++i) {
        final int threadNum = i;
        pool.execute(new Runnable() {

            @Override
            public void run() {
                try {
                    //获得许可
                    seam.acquire();
                    System.out.println(threadNum);
                    Thread.sleep(1000);
                    //释放许可
                    seam.release();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }

            }
        });
    }
    pool.shutdown();
}

//acquire和release还有下面这些用法
//一次获取2个
seam.acquire(2);
//尝试获取1个
if(seam.tryAcquire()) {}
//尝试获取2个
if(seam.tryAcquire(2)) {}
//尝试获取1个,超时时间为1000ms
if(seam.tryAcquire(1000, TimeUnit.MILLISECONDS)) {}
//尝试获取10个,超时时间为1000ms
if(seam.tryAcquire(10, 1000, TimeUnit.MILLISECONDS)) {}
//释放10个
seam.release(10);

CyclicBarrier

这里写图片描述
与CountDownLatch类似,但是这个是相互等待,直到有指定数量线程准备完毕,然后一起执行
具体的看演示代码

public class CyclicBarrierExample1 {

    //创建CyclicBarrier 对象,目标数值为5
    private static CyclicBarrier cb = new CyclicBarrier(5);

    public static void main(String[] args) throws InterruptedException {
        ExecutorService pool = Executors.newCachedThreadPool();
        for(int i = 0; i < 10; ++i) {
            final int threadNum = i;
            //这里让当前线程暂停,然后一个一个显示,要不然线程会一起运行会一起显示
            Thread.sleep(1000);
            pool.execute(new Runnable() {

                @Override
                public void run() {
                    try {
                        race(threadNum);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    } catch (BrokenBarrierException e) {
                        e.printStackTrace();
                    }
                }
            });
        }
        pool.shutdown();
    }

    private static void race(int threadNum) throws InterruptedException, BrokenBarrierException {
        //模拟等待,这里可以不写
        Thread.sleep(1000);
        System.out.println(threadNum + " is ready");
        //调用wait方法,让值加1,当有5个线程执行这个方法后,则会输出continue 
        cb.await();
        System.out.println(threadNum + " continue");
    }
}


//await方法也可以设定超时时间,超过后就直接执行,不必等待
private static void race(int threadNum) throws InterruptedException {
        Thread.sleep(1000);
        System.out.println(threadNum + " is ready");
            //超时后会抛出异常,要try住,要不然后面的代码无法执行
            try {
                cb.await(2000, TimeUnit.MILLISECONDS);
            } catch (BrokenBarrierException e) {
                //e.printStackTrace();
            } catch (TimeoutException e) {
                //e.printStackTrace();
            }
        System.out.println(threadNum + " continue");
    }

//CaclicBarrier还可定义一个方法, 再达到指定数值后优先执行
private static CyclicBarrier cb = new CyclicBarrier(5, new Runnable() {

        @Override
        //在达到5后会执行这个方法,执行一次,然后再去执行之前的5个线程的方法
        public void run() {
            System.out.println("callback");
        }
    });

ReentrantLock

这里写图片描述
还是之前那个计数的例子

private  static void add() {
        //显示的加锁和解锁即可
        lock.lock();
        ++count;
        lock.unlock();
    }

//默认是不公平的锁
Lock lock = new ReentrantLock();
public ReentrantLock() {
        sync = new NonfairSync();
    }
//参数了加true即为公平锁,获得锁的顺序,按照线程申请获得锁的顺序
Lock lock = new ReentrantLock(true);

//看下面的例子
public class LockExample2 {

    //请求总数
    public static int clientTotal = 10;

    //此时为公平锁
    private final static Lock lock = new ReentrantLock(true);

    public static void main(String[] args) throws InterruptedException {
        ExecutorService es = Executors.newCachedThreadPool();
        //信号量
        for(int i = 0; i < clientTotal; ++i) {
            final int num = i;
            es.execute(new Runnable() {
                @Override
                public void run() {
                        show(num);
                }
            });
        }
        es.shutdown();
    }

    private  static void show(int num) {
        //表示开始申请获得锁
        System.out.println(num + "---进入");
        lock.lock();
        //真正获得了锁
        System.out.println(num + "---获得锁");
        System.out.println(num);
        lock.unlock();
    }
}
//输出结果,进入顺序和获得锁的顺序一致
1---进入
4---进入
5---进入
3---进入
8---进入
0---进入
2---进入
7---进入
9---进入
6---进入
1---获得锁
4---获得锁
5---获得锁
3---获得锁
8---获得锁
0---获得锁
2---获得锁
7---获得锁
9---获得锁
6---获得锁

//改成非公平锁,发现获得锁的顺序和进入的顺序不一致
2---进入
3---进入
1---进入
0---进入
5---进入
2---获得锁
4---进入
8---进入
5---获得锁
6---进入
7---进入
9---进入
3---获得锁
1---获得锁
0---获得锁
4---获得锁
8---获得锁
6---获得锁
7---获得锁
9---获得锁


//lock.lockInterruptibly()和lock.lock();
//lock不会去处理中断,在获取到锁之后才会处理中断
//lockInterruptibly在获取锁的过程中就会响应中断
public static void main(String[] args) throws InterruptedException {
        final Lock lock=new ReentrantLock();
        //main函数先获取锁
        lock.lock();
        Thread.sleep(1000);
        Thread t1=new Thread(new Runnable(){
            @Override
            public void run() {
                try {
                    //这里再获取锁线程中断会抛出异常,改成lock.lock()就不会异常,会先获取所再处理异常
                    lock.lockInterruptibly();
                } catch (InterruptedException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
                System.out.println(Thread.currentThread().getName()+" interrupted.");
            }
        });
        t1.start();
        Thread.sleep(1000);
        //这里去中断线程,让她抛出异常
        t1.interrupt();
    }

//Lock的await对应于Object.wait,signal对应于Object.notify,signalAll对应于Object.notifyAll。

BlockingQueue

这里写图片描述

具体的实现类有ArrayBlockingQueue,LinkedBlockingQueue,DelayQueue,PriorityBlockingQueue,SynchronousQueue

可以看看这个文章: https://www.cnblogs.com/tjudzj/p/4454490.html

//ArrayBlockingQueue实现生产者消费者
public class ArrayBlockingQueueTest {

    public static final ArrayBlockingQueue<Integer> queue = new ArrayBlockingQueue<>(5);

    public static final int total = 100;

    public static void main(String[] args) {
        new Thread(new Runnable() {

            @Override
            public void run() {
                // 消费者
                while (true) {
                    try {
                        Thread.sleep(1000);
                        // 使用take方法当队列为空会阻塞
                        Integer take = queue.take();
                        System.out.println(take);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }

            }
        }).start();
        new Thread(new Runnable() {

            @Override
            public void run() {
                // 生产者
                for (int i = 0; i < total; ++i) {
                    try {
                        //put方法当容量满了会阻塞
                        queue.put(i);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }

            }
        }).start();
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值