`

java多线程编程——同步器Semaphore(一)

阅读更多
网上关于解释Semaphore用法的代码很多,但是都不能运行或者运行错误。下面的例子是经过我自己运行过的。而且我详细的注释了下各个变量和方法的用途。希望对大家有用,一起研究。
import java.util.concurrent.Semaphore;

/**
 *
 * @author Administrator
 *
 */
public class PoolSemaphoreDemo {
	private static final int MAX_AVAILABLE = 5;
	private final Semaphore available = new Semaphore(MAX_AVAILABLE, true);

	public static void main(String[] args) {
		final PoolSemaphoreDemo pool = new PoolSemaphoreDemo();
		Runnable runner = new Runnable() {
			public void run() {
				try {
					Object o;
					o = pool.getItem();

					Thread.sleep(1000);// 表示该线程睡眠1秒钟,即改线程不去竞争cpu处理时间1秒钟

					pool.putItem(o);
				} catch (InterruptedException e) {
					e.printStackTrace();
				}
			}
		};
		// 将上述线程重复执行10次
		for (int i = 0; i < 10; i++) {
			Thread t = new Thread(runner, "t" + i);
			t.start();
		}
	}

	/**
	 * 从字符串池中取得最近一个可用的字符串资源,同时将标志位池中的状态设为true,表示有线程正在使用。
	 *
	 * @return
	 * @throws InterruptedException
	 */
	public Object getItem() throws InterruptedException {
		System.out.println("线程:" + Thread.currentThread().getName()
				+ "开始从字符串资源池中取数据");
		available.acquire();
		return getNextAvailableItem();
	}

	/**
	 * 将x对应的标志位池的状态修改为false,然后释放改字符串资源供其他线程读取
	 *
	 * @param x
	 */
	public void putItem(Object x) {
		if (markAsUnused(x)) {
			available.release();
			System.out.println("线程:" + Thread.currentThread().getName()
					+ "已经释放资源");
		}
	}

	// 需要循环取的字符串池
	protected Object[] items = { "AAA", "BBB", "CCC", "DDD", "EEE" };
	// 字符串池对应的标志位池,如果为true表示正在使用,其他线程不可用。如果为false,则表示其他线程可以用
	protected boolean[] used = new boolean[MAX_AVAILABLE];

	/**
	 * 根据标志位数组得到items中有效的字符串
	 *
	 * @return
	 */
	protected synchronized Object getNextAvailableItem() {
		for (int i = 0; i < MAX_AVAILABLE; ++i) {
			if (!used[i]) {
				used[i] = true;
				System.out.println("线程:" + Thread.currentThread().getName()
						+ "从字符串池中取得资源:" + items[i]);
				return items[i];
			}
		}
		return null;
	}

	/**
	 * 根据item将对应位置的标志位的值改为false
	 *
	 * @param item
	 * @return
	 */
	protected synchronized boolean markAsUnused(Object item) {
		for (int i = 0; i < MAX_AVAILABLE; ++i) {
			if (item == items[i]) {
				if (used[i]) {
					used[i] = false;
					System.out.println("线程:" + Thread.currentThread().getName()
							+ "开始向字符串池中放入资源:" + items[i]);
					return true;
				} else
					return false;
			}
		}
		return false;
	}

}


Semaphore的用途中需要注意的就是,当release()或者acquire()时,如果当前线程不能获取到资源,那么当前线程会阻塞。知道获取到资源为止,这点可以从输出结果中可以看到。

下面是运行结果

    线程:t0开始从字符串资源池中取数据
    线程:t0从字符串池中取得资源:AAA
    线程:t1开始从字符串资源池中取数据
    线程:t1从字符串池中取得资源:BBB
    线程:t3开始从字符串资源池中取数据
    线程:t3从字符串池中取得资源:CCC
    线程:t5开始从字符串资源池中取数据
    线程:t5从字符串池中取得资源:DDD
    线程:t7开始从字符串资源池中取数据
    线程:t7从字符串池中取得资源:EEE
    线程:t9开始从字符串资源池中取数据
    线程:t2开始从字符串资源池中取数据
    线程:t4开始从字符串资源池中取数据
    线程:t6开始从字符串资源池中取数据
    线程:t8开始从字符串资源池中取数据
    线程:t0开始向字符串池中放入资源:AAA
    线程:t0已经释放资源
    线程:t9从字符串池中取得资源:AAA
    线程:t1开始向字符串池中放入资源:BBB
    线程:t1已经释放资源
    线程:t3开始向字符串池中放入资源:CCC
    线程:t3已经释放资源
    线程:t2从字符串池中取得资源:BBB
    线程:t4从字符串池中取得资源:CCC
    线程:t5开始向字符串池中放入资源:DDD
    线程:t5已经释放资源
    线程:t7开始向字符串池中放入资源:EEE
    线程:t7已经释放资源
    线程:t6从字符串池中取得资源:DDD
    线程:t8从字符串池中取得资源:EEE
    线程:t9开始向字符串池中放入资源:AAA
    线程:t9已经释放资源
    线程:t4开始向字符串池中放入资源:CCC
    线程:t4已经释放资源
    线程:t2开始向字符串池中放入资源:BBB
    线程:t2已经释放资源
    线程:t8开始向字符串池中放入资源:EEE
    线程:t8已经释放资源
    线程:t6开始向字符串池中放入资源:DDD
    线程:t6已经释放资源
分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics