6.2阻碍循环(Cyclic Barriers)

 一个cyclicbarrier让一堆的线程处于等待状态,它们彼此之间会有相同的阻碍点。这个阻碍是循环的,因为当等待的线程等到释放且,它可能会被重复利用。这个同步器在应用的程序中是非常有用的,它会执行一个固定大小的线程,偶尔必须等待每一个线程。

     java.util.concurrent.CyclicBarrier类继续一个循环的阻碍同步器。你可以通过执行这个类的CyclicBarrier(int parties)的构造器去明确实例化一个CyclicBarrier的实例。当parties的值小于1时,这个构造器将会抛出IllegalArgumentException。

     实际上你也执行CyclicBarrier(int parties, Runnabl barrierAction)的构造器去初始化一个循环的阻碍部分;其中的当阻碍被执行时,barrierAction将会执行。换句话说,parties -1个线程在等待,当多个线程到达时,到达的线程将会执行barrierAction和所有线程都会向前执行。这个runnable在所有线程都在执行时,而去更新分享的状态是非常的用的。当parties的值小于1时,就会抛出IllegalArgument的错误。(在前面的构造器执行这个构造器时,如果放入的barrierAction为null,那么当阻碍释放后,将没的线程会被执行。)

     CyclicBarrier也提供了如下的方法:

1)        int await():强迫正在请求的线程处于等待状态,直到所有部分在cyclic barrier中都执行await()的方法。当它或其它等待线程被打断,或其它线程在等待时超时,或在这个cyclic barrier中执行reset()的方法,那么在请求的线程会停止等待。如果正在请求的线程自己在进行执行时被打断,或在等待中被打断,这个方法将会抛出InterruptedException,并且请求的线程打断状态会被清空。任何线程在等待时被执行reset()的方法,或执行await()时被打断,或任何等待线程被打断,那么将会抛出BrokenBarrierException.当在等待时被打断,或者等待的线程抛出BrokenBarrierException,那么障碍(barrier)都会处于打断状态。如果请求的线程是最后一个到达,和构造器的barrierAction不为null,在允许其它线程继续执行前,将会让请求的线程去执行。这个方法将会返回请求线程的索引值,这里的索引getParties()-1说明从第一个线程到达到最后一个线程的达到。

2)        int await(long timeout,TimeUnit unit):这个方法与前面的方法是相似的,唯一不一样的是,它让你明确要多长时间让请求的线程进入到等待状态。在线程等待期间而超时了,那么将会抛出java.util.concurrent.TimeoutException.

3)        int getNumberWaiting():返回当前阻碍下等待的线程数量。这个方法对于打debug和输出信息很有用。

4)        int getParties():返回需要调用障碍(barrier)的数量。

5)        boolean isBroken():当一个或更多个部分被这个barrier打断,因为打断、超时、重置,或因为异常的抛出错误,这个方法将会返回true,其它情况返回false.

6)        void reset():重置这个障碍(barrier)去初始化它的状态。如果任何在障碍(barrier)中等待,那么将会抛出BrokenBarrierException.

 Cyclicbarriers在平形分隔的情况是很有用的。当一个长任务被分解为多个子任务,然后将子任务执行的结果再合并成一个结果返回。如下的Listing6-2的例子。

Listing6-2

package com.owen.thread.chapter6;

import java.util.concurrent.BrokenBarrierException;
import java.util.concurrent.CyclicBarrier;

public class CyclicBarrierDemo
{

	public static void main(String[] args)
	{
		float[][] matrix = new float[3][3];
		int counter = 0;
		for (int row = 0; row < matrix.length; row++)
			for (int col = 0; col < matrix[0].length; col++)
				matrix[row][col] = counter++;
		dump(matrix);
		System.out.println();
		Solver solver = new Solver(matrix);
		System.out.println();
		dump(matrix);
	}

	static void dump(float[][] matrix)
	{
		for (int row = 0; row < matrix.length; row++)
		{
			for (int col = 0; col < matrix[0].length; col++)
				System.out.print(matrix[row][col] + " ");
			System.out.println();
		}
	}
}

class Solver
{
	final int N;
	final float[][] data;
	final CyclicBarrier barrier;

	class Worker implements Runnable
	{
		int myRow;
		boolean done = false;

		Worker(int row)
		{
			myRow = row;
		}

		boolean done()
		{
			return done;
		}

		void processRow(int myRow)
		{
			System.out.println("Processing row: " + myRow);
			for (int i = 0; i < N; i++)
				data[myRow][i] *= 10;
			done = true;
		}

		@Override
		public void run()
		{
			while (!done())
			{
				processRow(myRow);
				try
				{
					barrier.await();
				} catch (InterruptedException ie)
				{
					return;
				} catch (BrokenBarrierException bbe)
				{
					return;
				}
			}
		}
	}

	public Solver(float[][] matrix)
	{
		data = matrix;
		N = matrix.length;
		barrier = new CyclicBarrier(N, new Runnable()
		{
			@Override
			public void run()
			{
				mergeRows();
			}
		});

		for (int i = 0; i < N; ++i)
			new Thread(new Worker(i)).start();
		waitUntilDone();
	}

	void mergeRows()
	{
		System.out.println("merging");
		synchronized ("abc")
		{
			"abc".notify();
		}
	}

	void waitUntilDone()
	{
		synchronized ("abc")
		{
			try
			{
				System.out.println("main thread waiting");
				"abc".wait();
				System.out.println("main thread notified");
			} catch (InterruptedException ie)
			{
				System.out.println("main thread interrupted");
			}
		}
	}
}

首先主线程创建一个浮点型的数组,然后通过dump的方法,将创建的数组值输出。然后线程会去实例化Solver的对象,这里会分隔线程去计算每一行的值。也就是说修改原告数组内的值,只是按行分隔修改。

     Solver出现一个构造器,这个构造器中会去接收数组的值的,并且保存它的引用,当然还就是定义一个参数N去保存数组的大小。构造器创建一个有N部分和一个障碍(barrier)的执行动作的cyclic barrier。在障碍(barrier)的执行中,是将数组计算的所有行的结果合并放入到数组中的。最后,构造器创建一个工作的线程,这个工作线程会被切分多个工作执行,就是去修改每一行的矩阵值。构造器会处于等待状,直到所有的工作都完成。

     Worker会重复地去执行run()方法,执行run()方法会去执行processRow()的方法,这个方法会明确去修改矩阵行的值,直到done()返回true的值,方法才会停止执行。当明确processRow()的方法执行完了,那么就会执行await()的方法,线程就不能继续前进。

     最为关键的是,所有工作线程都会执行await()的方法。当最后一个工作线程执行好了矩阵的修改后,就会执行await()的方法,然后触发障碍(barrier)的动作,使用刚刚执行的所有工作线程合并成一个矩阵的结果。在这个例子是,合并不是必须的,但是在更为复杂的例子中,合并是必须的。

     最后任务执行mergeRows()的方法,去唤醒主线程执行Solver的构造器。这个线程连接着一个字符串“abc”对象,使线程处于等待状态。调用notify()的方法,仅仅是唤醒在这个监听器中的等待线程。

     执行上面的代码,你可能会得到相似的结果:

0.0 1.0 2.0 
3.0 4.0 5.0 
6.0 7.0 8.0 

Processing row: 0
main thread waiting
Processing row: 1
Processing row: 2
merging
main thread notified

0.0 10.0 20.0 
30.0 40.0 50.0 
60.0 70.0 80.0



 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值