7.CountDownLatch&Semaphore的应用

7.CountDownLatch&Semaphore的应用

1.0 Semaphore是什么?

Semaphore 是信号量的意思,它的作用是控制访问特定资源的线程数目,底层依赖 AQS 的状态 State,是在生产当中比较常用的一个工具类。

有“控制访问特定的资源的线程数目”,可以知道当一个并发量很大的服务访问一个并发量小的服务时,可以用Semaphore 做限流功能,她的一个经典场景就是服务限流(Hystrix 里限流就是基于信号量方式) 。

1.1 Semaphore使用
1.1.1构造方法
 public Semaphore(int permits)
 public Semaphore(int permits, boolean fair)
  • permits表示许可线程的数量
  • fair表示公平性,如果这个设为true的话,下次执行的线程会是等待最久的线程
1.1.2重要方法
public void acquire(() throws InterruptedException
public void release() 
tryAcquire (int args,long timeout, TimeUnit unit)
  • acquire()表示阻塞并获取许可
  • release()表示释放许可
  • tryAcquire 当前线程在限定的时间内尝试去获取 1 个许可证,得不到不等待。

使用例子如下:

import java.util.Date;
import java.util.concurrent.Semaphore;  
  
public class SemaphoreRunner {  
    public static void main(String[] args) {  
        Semaphore semaphore = new Semaphore(2);  
        for (int i = 0; i < 10; i++) {  
            new Thread(new Task(semaphore, "任务:" + i)).start();  
        }  
    }
    static class Task extends Thread {  
        Semaphore semaphore;  
  
        public Task(Semaphore semaphore, String tname) {  
            this.semaphore = semaphore;  
            this.setName(tname);  
        }
        @Override  
        public void run() {  
            try {  
                //获得公共资源
                semaphore.acquire();  
                System.out.println(this.getName() + "获得许可证 at time:" + new Date());  
                Thread.sleep(3000);  
                //释放公共资源
                semaphore.release();
                System.out.println(this.getName() + "释放许可证 at time:" + new Date());
            } catch (InterruptedException e) {  
                e.printStackTrace();  
            }  
  
        }  
    }  
}

总结:一次只有两个线程执行acquire,只有线程进行release方法后才会有别的线程执行acquire。

2.0 CountDownLatch使用场景及例子
2.1 CountDownLatch 是什么?

​ CountDownLatch 这个类能够使一个线程等待其他线程完成各自的工作后在执行。例如,应用程序的主线程希望在负责启动框架服务的线程已经启动所有的框架服务之后再执行。

2.2 CountDownLatch 工作流程

​ CountDownLatch是通过一个计数器来实现的,计数器的初始值为线程的数量。每当一个线程完成自己的任务后,计数器的值就会减少1。当计数器的值到达0时,它标识所有的线程已经完成了任务,然后在闭锁上等待的线程就可以恢复执行任务。

2.3 CountDownLatch 常用方法:
public void await() throws InterruptedException {  
    //调用await()方法的线程会被挂起,它会等待直到count值为0才继续执行  
}  
public boolean await(long timeout, TimeUnit unit) throws InterruptedException {  
    //和await()类似,只不过等待一定的时间后count值还没变为0的话就会继续执行  
}  
public void countDown() {  
    //将count值减1  
}

例子如下:

public class CountDownlatchRunner {  
    public static void main(String[] args) throws InterruptedException {  
        CountDownLatch countDownLatch = new CountDownLatch(5);  
        for(int i=0;i<5;i++){  
            new Thread(new ReadNum(i,countDownLatch)).start();  
        }  
        // 等待所有线程结束
        countDownLatch.await();  
        System.out.println("线程执行结束。。。。");  
    }  
  
    static class ReadNum  implements Runnable{  
        private int id;  
        private CountDownLatch latch;  
        public ReadNum(int id,CountDownLatch latch){  
            this.id = id;  
            this.latch = latch;  
        }  
        @Override  
        public void run() {  
            synchronized (this){  
                System.out.println("id:"+id);  
                latch.countDown();  
                System.out.println("线程组任务"+id+"结束,其他任务继续");  
            }  
        }  
    }  
}

3.0 CycliBarrier 的应用

​ 栅栏屏障,让一组线程到达一个屏障(又称同步点)时被阻塞,直到最后一个线程到达屏障时,屏障才会开门,所有被屏障拦截的线程才会继续运行。

​ CycliBarrier默认构造方法CycliBarrier(int parties),其参数表示屏障拦截的线程数量,每个线程调用await方法告诉CycliBarrier已经到达屏障,然后当前线程阻塞。

// 指定了N个线程互相等待
public CyclicBarrier(int parties) { }
// 指定N个线程在任务 barrierAction  处互相等待
public CyclicBarrier(int parties, Runnable barrierAction) { } 
public int await() throws InterruptedException, BrokenBarrierException {
        //挂起当前线程,直至所有线程都到达barrier状态再同时执行后续任务;
}
public int await(long timeout, TimeUnit unit)throws InterruptedException,BrokenBarrierException,TimeoutException {
//让这些线程等待至一定的时间,如果还有线程没有到达barrier状态
//就直接让到达barrier的线程执行后续任务
}
3.1应用场景

​ 可以用于多线程计算数据,最后合并计算结果的场景。例如,用一个Excel保存用户的所有银行流水,每个sheet保存一个账户一年的每笔银行流水,现在需要统计用户的日均银行流水,先用多线程处理每个sheet里的银行流水,得到每个sheet的日均银行流水,最后再用barrierAction用这些线程的计算结果,计算出整个Excel的日均银行流水。

import java.util.concurrent.CyclicBarrier;

public class CyclicBarrierTest {
	public static void main(String[] args) throws InterruptedException {
		CyclicBarrier cyclicBarrier = new CyclicBarrier(5, new Runnable() {
			@Override
			public void run() {
				System.out.println("线程组执行结束");
			}
		});
		for (int i = 0; i < 5; i++) {
			new Thread(new ReadNum(i,cyclicBarrier)).start();
		}
		//CyclicBarrier 可以重复利用,
		// 这个是CountDownLatch做不到的
//        for (int i = 11; i < 16; i++) {
//            new Thread(new readNum(i,cyclicBarrier)).start();
//        }
	}
	static class ReadNum  implements Runnable{
		private int id;
		private CyclicBarrier cyc;
		public ReadNum(int id,CyclicBarrier cyc){
			this.id = id;
			this.cyc = cyc;
		}
		@Override
		public void run() {
			synchronized (this){
				System.out.println("id:"+id);
				try {
				// 线程等待,直到5各线程都运行到这里再一起执行
					cyc.await();
					System.out.println("线程组任务" + id + "结束,其他任务继续");
				} catch (Exception e) {
					e.printStackTrace();
				}
			}
		}
	}
}

4.总结:

BlockingQueue、Semaphore 和CountDownLatch 线程之间通信的桥梁和工具 。Semaphore可以应用到服务调用之间的限流;CountDownLatch和CyclicBarrier区别如下:CountDownLatch是以减数的方式而CyclicBarrier是以加数的方式;CountDownLatch强调的是一个等待其他多个线程而CyclicBarrier是一组线程相互等待;CountDownLatch不可重复利用而CyclicBarrier可重复利用。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
### 回答1: sun.misc.unsafe.park(native me) 是Java中的一个方法,它是用来阻塞当前线程的。具体来说,它会使当前线程进入等待状态,直到被唤醒或者被中断。这个方法通常用于实现线程的同步和互斥。 ### 回答2: sun.misc.unsafe.park(native me 是一个Java API中的方法,它通过使用Unsafe类的park方法来使当前线程进入休眠状态。在这个方法中,native关键字表示它是由本地代码实现的,也就是说具体的实现是由底层的操作系统提供的。 调用sun.misc.unsafe.park(native me 方法可以实现线程的等待和唤醒操作。当当前线程执行到这个方法时,会立即进入休眠状态,暂停自己的执行,直到其他线程通过调用Unsafe类的unpark方法唤醒它。 这个机制通常用于线程同步的场景,可以实现线程之间的协作。比如,一个生产者线程通过调用Unsafe类的park方法进入休眠状态,等待某个条件满足后再继续执行;而一个消费者线程在满足某个条件后,通过调用Unsafe类的unpark方法唤醒生产者线程,使其恢复执行。 需要注意的是,sun.misc.unsafe.park(native me 方法通常不建议直接使用,因为它是一个内部API,可能会在未来的版本中被移除或者修改。在实际应用中,可以使用更高级的并发工具,如Lock和Condition、CountDownLatchSemaphore等来实现线程的等待和唤醒操作,这些API提供了更加安全和可靠的线程同步机制。 ### 回答3: sun.misc.unsafe.park(native me)是Java中的一个方法,它是由sun.misc.Unsafe类提供的。该方法主要用于线程的阻塞等待。 在Java中,线程可以通过调用park方法进入阻塞状态,直到某个条件满足或者其他线程唤醒它。park方法是一种低级的阻塞机制,它不会占用CPU资源,因此适用于一些需要较长等待时间的场景。 使用park方法时,我们需要传入一个native me参数。native me是指要阻塞的线程对象,也就是当前执行park方法的线程自身。 park方法可以通过其他线程的unpark方法来唤醒被阻塞的线程。unpark方法会给指定的线程一个许可证,使得park方法立即返回。 使用park方法进行线程的阻塞等待可以提高线程的效率和性能,避免了一直占用CPU资源。 需要注意的是,sun.misc.unsafe.park(native me)方法属于sun.misc包下的不稳定的、不建议直接使用的API。在实际开发中,应该尽量避免使用这些API,而是使用Java提供的高级并发类库,如java.util.concurrent包下的Locks和Conditions,或者使用更高层次的并发框架,如线程池。这些类库和框架提供了更稳定、易用且可扩展的线程同步和阻塞等待机制。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

苹水相峰

你的打赏是对我最大的肯定

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值