您好!欢迎来到爱源码

爱源码

热门搜索: 抖音快手短视频下载   

线程协作 <源码交易>

  • 时间:2022-07-09 00:15 编辑: 来源: 阅读:296
  • 扫一扫,手机访问
摘要:线程协作 <源码交易>
1.信号量信号量信号量是信号量最重要的功能之一,就是控制需要限制并发访问的资源。 具体来说,semaphore将维护“许可证”的计数,线程必须在访问共享资源之前获得许可证。 一个线程可以从信号量中“获得”一个许可证。一旦线程得到,信号量持有的许可证就会被转移,所以信号量手里剩余的许可证就会减一。 类似地,线程也可以“释放”许可证。如果线程释放了许可证,则该许可证相当于被返回给信号量,因此信号量中可用的许可证数量增加了一个。 当信号量拥有的许可证数量减少到0时,如果下一个线程还想获得一个许可证,那么这个线程就必须等到之前获得许可证的线程被释放,它就无法获得。 因为线程在获得许可之前不能进一步访问受保护的共享资源,所以控制了资源的并发访问,这就是整个思路。 1.用法:public semaphore(int permissions,boolean fair)的第一个参数是许可证的数量,另一个参数是是否可以公平。 如果第二个参数为真,说明这是一个公平策略,它会把之前一直在等待的线程放入队列,当一个新的许可证到来时,它会把这个许可证按顺序发给之前一直在等待的线程;如果这个构造函数的第二个参数传入false,那么就代表了一个不公平的策略,有可能插队,也就是说后面发出请求的线程可能会先得到许可。 2.acquire()和acquireUninterruptibly()这两个方法的作用是获取一个许可证,也就是说只有这个方法能够成功执行,才能进一步访问调用这个代码背后的慢速服务的方法。 如果此时信号量没有剩余的许可证,线程将在acquire方法的这行代码中等待,因此它不会进一步执行下面调用slow service的方法。 我们就是这样保护我们的慢服务的。 acquire()和acquireUninterruptibly()的区别在于是否能响应中断。 Acquire()可以支持中断,也就是说,如果这个线程在获取信号量的过程中被中断,就会跳出acquire()方法,停止尝试获取。 acquireUninterruptibly()方法不会被中断。 3.release()发布许可4。public boolean try acquire()try acquire与前面细节锁的trylock思路一致。就是想办法考取牌照,相当于看看现在有没有免费的牌照。如果有,就去拿。如果你现在拿不到,也没关系。不一定非要卡住,可以做点别的。 5.public Boolean try acquire(long time out,time unit unit)也有一个重载的方法,在这个方法中传递超时。 例如,如果来电时间为3秒,则表示最多等待3秒。如果在等待期间取得许可证,将继续执行。如果超时时间到了,无法获得许可,则认为获取失败,返回false。 6.availablePermits()该方法用于查询可用许可证的数量,并返回一个整数结果。 特殊用法:一次获得或释放多个许可证。参数2在semaphore.acquire(2)中传递,这被称为一次获得两个许可证。 同时,释放也是一样的。semaphore.release(3)相当于一次发布三个许可证。 为什么要这么做?我们来列举一个使用场景。 比如第一个任务A(任务A)会调用method1(),消耗了很多资源,而任务B调用method 2,但是这个方法并不是特别消耗资源。 在这种情况下,假设我们有五个许可证,只有一个线程可以同时调用方法1,或者最多五个线程可以同时调用方法2,但是方法1和方法2不能同时调用。 因此,我们要求任务A一次获得五个许可证才能执行,而任务B只能获得一个许可证才能执行。 这样就避免了任务A和任务B同时运行,同时也很好的兼顾了效率,使得同一时间只允许一个线程访问方法2,那么资源就会被浪费掉,那么就相当于我们可以根据自己的需要适当的使用信号量许可证来分配资源。 信号量有几点需要注意。获取和发布的许可证数量应该尽可能一致。否则,比如每次获取两个许可但只释放一个许可或者不释放,那么semaphore中的许可就会慢慢消耗,最后semaphore中就没有许可了。那么其余的线程就不能再访问它了。可以在初始化期间设置公平性。如果设置为true,会更公平,但如果设置为false,总吞吐量会更高。 信号量支持跨线程和跨线程池,而且不是任何一个线程获得的许可证,所以必须是这个线程释放的。 事实上,对获取和释放许可证的线程没有任何要求。比如线程A获取许可证,然后由线程B释放,这是完全可以的,只要逻辑上说得过去。 二。CountDownLatch 1的主要方法的详细信息。公共倒计时闩锁(int count){ };它的构造函数是传入的参数,参数count是要求逆的数。 2.await()调用await()方法的线程开始等待,直到倒计时结束,也就是计数值为0的时候。 3.await(长时间超时,时间单位单位)await()有一个重载的方法,其中将传入一个超时参数。这个方法的功能类似于await(),但是超时可以在这里设置。如果超时,它将不再等待。 4.countDown()将值递减1,也就是将计数值减1,直到减为0,之前等待的线程就会被唤醒。 用法一个线程等待其他线程执行完再继续工作/* * *在这段代码中,我们构建了一个新的CountDownLatch *初始值为5,然后设置一个有5个固定线程的线程池*用for循环向这个线程池提交5个任务*每个任务代表一个运动员*这个运动员一开始会随机等待一段时间, 表示他在跑*然后打印出他已经跑完了*跑完之后,同样的,在主线程打印出“等待所有五个运动员跑完”这句话之后会调用countDown方法将计数减1 *会调用await()方法, 也就是说主线程会开始等待*在等待之前的所有子线程都执行完之后*它会认为所有人都跑完了*这个程序的运行结果如下:*等待所有五个运动员跑完 ......4号运动员已经跑完了全程。 三号运动员完成了比赛。 第一名运动员完成了比赛。 五号运动员完成了比赛。 第二名运动员完成了比赛。 *所有人都跑完了,比赛结束了。 */public class run demo 1 { public static void main(String[]args)throws interrupted exception { CountDownLatch latch = new CountDownLatch(5);ExecutorService service = executors . newfixedthreadpool(5);for(int I = 0;我& lt5;i++){ final int no = I+1;Runnable Runnable = new Runnable(){ @ Override public void run(){ try { thread . sleep((long)(math . random()* 10000));System.out.println(no+"运动员)完成比赛。 ");} catch(interrupted exception e){ e . printstacktrace();}最后{ latch . count down();} } };service . submit(runnable);} System.out.println("等待5名运动员全部跑完...");latch . await();System.out.println("大家都跑完了,比赛结束。 ");}}多个线程等待某个线程的信号,同时开始执行。/* * *首先它打印出来运动员有5秒准备*构建了CountDownLatch,倒数只有1 *一个5线程的线程池*以for循环的形式提交了5个任务*这5个任务在开始的时候都是让调用await()方法*主线程会先等待5秒*然后调用countDown方法*那5个任务之前已经调用过await()。所以这个程序的运行结果是这样的:*运动员有5秒准备* 2号运动员准备好,等待裁判发令枪* 1号运动员准备好,等待裁判发令枪* 3号运动员准备好,等待裁判发令枪* 4号运动员准备好,等待裁判发令枪* 5号运动员准备好,等待裁判发令枪* 5秒已过,开始!* 2号运动员开跑* 1号运动员开跑* 5号运动员开跑* 4号运动员开跑* 3号运动员开跑*/公开课run demo 2 public static void main(string[]args)抛出中断异常{system.out.println("运动员有5秒准备");CountDownLatch CountDownLatch = new CountDownLatch(1);ExecutorService service = executors . newfixedthreadpool(5);for(int I = 0;我& lt5;i++){ final int no = I+1;runnable = new runnable(){ @ override public void run(){ system . out . println(No+“运动员准备好,等待裁判发令枪”);请尝试{ countdownlatch . await();System.out.println(no+"运动员开始跑步");} catch(interrupted exception e){ e . printstacktrace();} } };service . submit(runnable);} thread . sleep(5000);System.out.println("五秒的准备时间过去了,发令枪响,比赛开始!");countdownlatch . count down();}}注意,刚才我们讲了两种用法。其实这两种用法并不是孤立的,我们甚至可以结合起来使用。比如我们用两个CountDownLatch,第一个初值是倍数,第二个初值是1,这样可以处理更复杂的业务场景;CountDownLatch不能重复使用。比如倒计时已经完成,下次还能继续倒计时吗?这可不行。如果有这个需求,可以考虑使用CyclicBarrier或developers创建一个新的CountDownLatch实例。 三。CyclicBarrier和CountdownLatch有什么异同?建造一个集合点。当一个线程执行await()时,它会转到这个聚集点,等待这个栅栏被撤销。 在预定数量的线程到达这个集合点之前,这个栅栏将被撤销,之前等待的线程将在这个时刻出发,继续执行剩余的任务。 举一个生活中的例子。 假设我们班去公园春游,会租三个人的自行车,每个人都可以骑。但是因为这辆自行车是三个人的,所以三个人骑一辆,从公园门口走到自行车站需要一段时间。 那么我们来模拟一下这个场景,写下面的代码:/* * *构建一个参数为3的CyclicBarrier,*参数为3意味着你需要等待三个线程到达这个集合点后再统一释放* for循环中打开了六个线程*每个线程中执行的Runnable对象都在下面的Task类中*首先你会打印出“同学XXX现在从大门出发去自行车站”*然后你会随机睡一段时间,这代表了从大门走到自行车站的时间*由于每个学生的行走速度不同,所以时间是用随机值模拟的*当所有学生到站时,比如某个学生到站*时,它会先打印出“同学某某到达自行车站, 开始等待剩下的人到达”*然后调用CyclicBarrier的await()方法*一旦它调用这个方法,就会卡在等待中*直到三个人走到一起才会继续往下走*一旦开始往下走,就意味着三个学生开始一起骑*所以打印出语句“某某开始骑”*运行这个程序, 结果如下:*同学1现在从大门出发去自行车站*同学3现在从大门出发去自行车站*同学4现在从大门出发去自行车站*同学5现在从大门出发去自行车站*同学6现在从大门出发去自行车站* 同学5到达自行车站,开始等待其余的到达*同学2到达自行车站,开始等待其余的到达*同学3开始骑车*同学5开始骑车*同学2开始骑车*同学6到达自行车站,开始等待其余的到达*同学4到达自行车站, 开始等待其余人到达*同学1到达自行车停靠点,等待其余人到达*同学1开始骑行*同学6开始骑行*同学4开始骑行*/Public class Cyclic barrier demo { Public static void main(string[]args){ Cyclic barrier Cyclic barrier = New Cyclic barrier(3); for(int I = 0;我& lt6;i++) {新线程(新任务(i + 1,cyclicBarrier))。start();} }静态类任务实现Runnable { private int id私人循环障碍循环障碍;public Task(int id,cyclic barrier cyclic barrier){ this . id = id;this . cyclic barrier = cyclic barrier;} @ override public void run(){ system . out . println(" classmate "+id+"现在从大门出发,去自行车岗");试试{ thread . sleep((long)(math . random()* 10000));System.out.println("同学"+id+"到达自行车站,开始等待其余人的到来);cyclic barrier . await();System.out.println("同学"+id+"开始循环");} catch(interrupted exception e){ e . printstacktrace();} catch(BrokenBarrierException e){ e . printstacktrace();}}}}执行操作BarrierAction公共循环屏障(int parties,runnable barrier action)。当参与方线程到达组装点时,这个动作将在继续执行之前执行。 循环屏障循环屏障=新循环屏障(3,new runnable(){ @ override public void run(){ system . out . println("已经集合了三个人,快走!");}});CyclicBarrier和CountDownLatch的异同可以阻塞一个或一组线程,直到满足某个预设条件,然后统一出发。不同的点作用在不同的物体上。CyclicBarrier必须等待固定数量的线程到达栅栏位置才能继续执行,而CountDownLatch只需要等待该数量递减计数到0。也就是说,CountDownLatch作用于事件,而CyclicBarrier作用于线程CountDownLatch是在调用countdown方法后减1,而CyclicBarrier是在一个线程开始等待后减1。 不同的可重用性CountDownLatch在递减计数到0并触发闩锁打开后不能再次使用,除非创建一个新的实例CyclicBarrier,可以重用。从刚才的代码可以看出,每三个学生到了之后就可以开始了,不需要创建新的实例。CyclicBarrier也可以随时调用reset方法进行重置。如果一个线程已经调用了await方法并在重置时开始等待,那么这些线程将抛出一个BrokenBarrierException异常。 不同的操作:CyclicBarrier具有操作barrierAction,但CountDownLatch没有此功能。


  • 全部评论(0)
资讯详情页最新发布上方横幅
最新发布的资讯信息
【技术支持|常见问题】1556原创ng8文章搜索页面不齐(2024-05-01 14:43)
【技术支持|常见问题】1502企业站群-多域名跳转-多模板切换(2024-04-09 12:19)
【技术支持|常见问题】1126完美滑屏版视频只能显示10个(2024-03-29 13:37)
【技术支持|常见问题】响应式自适应代码(2024-03-24 14:23)
【技术支持|常见问题】1126完美滑屏版百度未授权使用地图api怎么办(2024-03-15 07:21)
【技术支持|常见问题】如何集成阿里通信短信接口(2024-02-19 21:48)
【技术支持|常见问题】算命网微信支付宝产品名称年份在哪修改?风水姻缘合婚配对_公司起名占卜八字算命算财运查吉凶源码(2024-01-07 12:27)
【域名/主机/服务器|】帝国CMS安装(2023-08-20 11:31)
【技术支持|常见问题】通过HTTPs测试Mozilla DNS {免费源码}(2022-11-04 10:37)
【技术支持|常见问题】别告诉我你没看过邰方这两则有思想的创意广告! (2022-11-04 10:37)

联系我们
Q Q:375457086
Q Q:526665408
电话:0755-84666665
微信:15999668636
联系客服
企业客服1 企业客服2 联系客服
86-755-84666665
手机版
手机版
扫一扫进手机版
返回顶部