线程同步技术_四核八线程是什么意思

线程同步技术_四核八线程是什么意思线程同步器在执行线程任务时,时常会遇到需要多个线程执行完成之后,才进行下一步操作。线程中有三个工具可以实现此功能,下面进行一一介绍:(一) CountDownLatchCountDownLatch依赖

线程同步器   在执行线程任务时,时常会遇到需要多个线程执行完成之后,才进行下一步操作。线程中有三个工具可以实现此功能,下面进行一一介绍:   (一) CountDownLatch   CountDownLatch依赖于抽象同步队列实现,当new 一个countDownLatch对象时传入计数器参数,执行await方法时进入等待。计数器在每个线程执行完之后通过执行countDown方法减去1 ,直到所有线程执行完后计数器为0,此时await方法退出并进入下一步操作。   由于计数器是在线程中干完工作后减少的,所以在创建线程任务时需要将countDownLatch对象传入。   package concurrent.executorService; import java.util.concurrent.CountDownLatch; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; public class MyCountDownLatch { private ExecutorService executorService; private CountDownLatch countDown; public MyCountDownLatch(int poolSize, int countDownNum){ this.executorService = Executors.newFixedThreadPool(poolSize); this.countDown = new CountDownLatch(countDownNum); } public void useCountDownLatch() throws InterruptedException { long taskNum = this.countDown.getCount(); for(int i = 0; i < taskNum; i++){ executorService.submit(new MyTask(countDown, i)); } countDown.await(); } public class MyTask implements Runnable{ private CountDownLatch countDownLatch; private int taskSequence; public MyTask(CountDownLatch countDown, int i){ this.countDownLatch = countDown; this.taskSequence = i; } @Override public void run() { doTask(taskSequence); this.countDownLatch.countDown(); } } public void doTask(int taskSequence) { try{ Thread.sleep(1000); }catch (Exception e){ System.out.println(e.getMessage()); } System.out.println(“execute task job :” + taskSequence); } }   测试代码如下:   public class MyCountDownLatchTest extends TestCase { public void testUseCountDownLatch() throws InterruptedException { MyCountDownLatch myCountDownLatch = new MyCountDownLatch(5,3); myCountDownLatch.useCountDownLatch(); System.out.println(“所有任务已完成”); } }   测试结果:   execute task job :1   execute task job :2   execute task job :0   所有任务已完成       (二)CyclicBarrier   cyclicBarrier回环屏障也被成为栅栏,在创建cyclicBarrier对象时,需要传入计数器的值(设置的栅栏数)和需要等待所有线程完成之后要做的事情(Runnable接口)。 在每个线程执行完内部的工作之后执行await方法即将计数器减去1(跨过了一个栅栏),待到计数器的值为0时,就执行Runnable接口实现的方法。此外计数器为0 时,也会重新将计数器设置为原来的栅栏数,此举就是为了复用。   代码示例如下:   package concurrent.executorService; import java.util.concurrent.BrokenBarrierException; import java.util.concurrent.CyclicBarrier; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; public class MyCyclicBarrier { private CyclicBarrier cyclicBarrier; private ExecutorService service; private Integer integer = new Integer(1); public MyCyclicBarrier() { cyclicBarrier = new CyclicBarrier(2, () -> { System.out.println(“step ” + integer + ” finished”); ++integer; }); service = Executors.newFixedThreadPool(2); } public void useCyclicBarrier() { service.submit(() -> { System.out.println(Thread.currentThread().getName() + ” do step one”); cyclicBarrierAwait(); System.out.println(Thread.currentThread().getName() + ” do step two”); cyclicBarrierAwait(); System.out.println(Thread.currentThread().getName() + ” do step three”); cyclicBarrierAwait(); }); service.submit(() -> { System.out.println(Thread.currentThread().getName() + ” do step one”); cyclicBarrierAwait(); System.out.println(Thread.currentThread().getName() + ” do step two”); cyclicBarrierAwait(); System.out.println(Thread.currentThread().getName() + ” do step three”); cyclicBarrierAwait(); }); service.shutdown(); System.out.println(“over”); } private void cyclicBarrierAwait() { try { cyclicBarrier.await(); } catch (InterruptedException e) { e.printStackTrace(); } catch (BrokenBarrierException e) { e.printStackTrace(); } } }   测试代码如下:   public class MyCyclicBarrierTest extends TestCase { public void testUseCyclicBarrier() { MyCyclicBarrier cyclicBarrier = new MyCyclicBarrier(); cyclicBarrier.useCyclicBarrier(); } }   测试结果:   pool-1-thread-1 do step one   pool-1-thread-2 do step one   over   step 1 finished   pool-1-thread-1 do step two   pool-1-thread-2 do step two   step 2 finished   pool-1-thread-1 do step three   pool-1-thread-2 do step three   step 3 finished   从以上结果可以看出,主线程的执行顺序是不受栅栏影响的,栅栏只规定了线程中哪些步骤做完之后再去做栅栏中的Runnable接口的方法。此外,栅栏的计数器是可以复用的。       (三)Semaphore 信号量   信号量也是依赖于抽象同步队列实现的。在创建信号量对象时传入的计数器值是0,执行信号量的acquire方法时会传入一个参数,该参数表示计数器需要达到该值后才会退出等待,执行下一步操作。每个线程中通过执行信号量的release方法,将计数器加1.   package concurrent.executorService; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.Semaphore; public class MySemaphore { private Semaphore semaphore = new Semaphore(0); private ExecutorService service; public MySemaphore(){ service = Executors.newFixedThreadPool(2); } public void useSemaphore() throws InterruptedException { service.submit(() -> { System.out.println(Thread.currentThread().getName() + ” do step one”); semaphore.release(); }); service.submit(() -> { System.out.println(Thread.currentThread().getName() + ” do step one”); semaphore.release(); }); semaphore.acquire(2); service.shutdown(); System.out.println(“over”); } }   测试代码:   public class MySemaphoreTest extends TestCase { public void testUseSemaphore() throws InterruptedException { MySemaphore mySemaphore = new MySemaphore(); mySemaphore.useSemaphore(); } }   测试结果:   pool-1-thread-1 do step one   pool-1-thread-2 do step one   over   从这里可以看出Semphore和CountDownLatch的效果非常的类似。只是Semphore的计数器也是可以复用的。   (四) cyclicBarrier与CountDownLatch的区别   它的命名形象的表示了其能力属性,Count代表着计数,Down代表着计数器的递减操作,而Latch表示计数器递减后的结果动作。 它通常被应用于:允许一个或多个线程,等待其他一组线程完成操作,再继续执行。countDownLatch的计数器为0后,不可重用。 countDownLatch基于抽象同步队列, 三个重要的方法: //通过构造函数传递计数器的值,实际是传给了抽象队列同步器的state   public CountDownLatch(int count) { if (count < 0) throw new IllegalArgumentException(“count < 0”); this.sync = new Sync(count); } //减少锁存器的计数,如果计数达到零,则释放所有等待线程; 如果当前计数大于零,则递减。 public void countDown() { sync.releaseShared(1); } //将当前线程阻塞住,直到count值减为0才会放开执行 public void await() throws InterruptedException { sync.acquireSharedInterruptibly(1); }   cyclicBarrier:Cyclic是循环的意思而Barrier则表示栅栏、障碍的意思,字面的意思就是可循环的栅栏。 它经常被应用于:允许一组线程相互之间等待,达到一个共同点,再继续执行。可复用。 CyclicBarrier 的源码实现和 CountDownLatch 大同小异,CountDownLatch 基于 AQS 的共享模式的使用,而 CyclicBarrier 基于 ReentrantLock来实现的。 CyclicBarrier内部维护了parties和count变量,parties表示每次参与到一个Generation中需要被拦截的线程数量,而count是内部计数器,在初始化的时候count与parties相等,当每次调用await方法的时候计数器count就会减1,这和上文中的countDown类似。如果计数器为0, 唤醒所有线程,并进入下一个线程协调器。 private final ReentrantLock lock = new ReentrantLock(); private final Condition trip = lock.newCondition();   //指定每次需要进行协调的线程个数以及解除阻塞之后需要后续执行的任务   public CyclicBarrier(int parties, Runnable barrierAction) { if (parties <= 0) throw new IllegalArgumentException(); this.parties = parties; this.count = parties; this.barrierCommand = barrierAction; } //指定每次需要进行协调的线程个数 public CyclicBarrier(int parties) { this(parties, null); } private int dowait(boolean timed, long nanos) throws InterruptedException, BrokenBarrierException, TimeoutException { final ReentrantLock lock = this.lock; lock.lock(); try { final Generation g = generation; if (g.broken) throw new BrokenBarrierException(); if (Thread.interrupted()) { breakBarrier(); throw new InterruptedException(); } //如果计数器为0, 唤醒所有线程,并进入下一个线程协调器。 int index = –count; if (index == 0) { // tripped boolean ranAction = false; try { final Runnable command = barrierCommand; if (command != null) command.run(); ranAction = true; nextGeneration(); return 0; } finally { if (!ranAction) breakBarrier(); } } //计数器不为0,继续进行循环 for (;;) { try { if (!timed) trip.await(); else if (nanos > 0L) nanos = trip.awaitNanos(nanos); } catch (InterruptedException ie) { if (g == generation && ! g.broken) { breakBarrier(); throw ie; } else { // We’re about to finish waiting even if we had not // been interrupted, so this interrupt is deemed to // “belong” to subsequent execution. Thread.currentThread().interrupt(); } } if (g.broken) throw new BrokenBarrierException(); if (g != generation) return index; if (timed && nanos <= 0L) { breakBarrier(); throw new TimeoutException(); } } } finally { lock.unlock(); } } private void nextGeneration() { // signal completion of last generation trip.signalAll(); // set up next generation count = parties; generation = new Generation(); } private void breakBarrier() { generation.broken = true; count = parties; trip.signalAll(); } 区别 CountDownLatch CyclicBarrier 计数方式   递减计数   调用countDown,N-1   加法计数   调用await, N+1 可重复利用性 不可重复利用 可重复利用 初始值 初始值为N,N>0 N为0 阻塞条件 N>0, 调用await一直阻塞 N小于指定值 何时释放等待线程 计数为0时 计数达到指定的N值 是否阻塞主进程 会 不会,只会阻塞子进程

2024最新激活全家桶教程,稳定运行到2099年,请移步至置顶文章:https://sigusoft.com/99576.html

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请联系我们举报,一经查实,本站将立刻删除。 文章由激活谷谷主-小谷整理,转载请注明出处:https://sigusoft.com/49808.html

(0)
上一篇 2024年 9月 3日
下一篇 2024年 9月 3日

相关推荐

关注微信