AQS的例子分析二

这个例子不单是让我们更了解AQS的具体使用,还明白了AQS类中state字段的作用

因为tryAcquire这个方法是我们自己实现的,方法作用是尝试获取资源,根据我们自己的逻辑来决定是否获取成功.

像下面这个例子,我的逻辑就是当资源小于0时,线程就获取失败,所以我先调用setState方法设初始值放到state字段,值为N,然后每来一个线程就将N-1,然后判断是否N-1小于0,从而实现线程资源的控制

工具类

/*
 * 设计一个同步工具,该工具在同一时刻,只能有两个线程能够并行访问,超过限制的其他线程进入阻塞状态。
 * 对于这个需求,可以利用同步器完成一个这样的设定,定义一个初始状态,为2,一个线程进行获取那么减1,一个线程释放那么加1,状态正确的范围在[0,1,2]三个之间
 * 当在0时,代表再有新的线程对资源进行获取时只能进入阻塞状态(注意在任何时候进行状态变更的时候均需要以CAS作为原子性保障)。
 * 由于资源的数量多于1个,同时可以有两个线程占有资源
 */
public class QueueSynchronizerTest implements Lock {

	private final Sync sync = new Sync(2);

	private static final class Sync extends AbstractQueuedSynchronizer {
		private static final long serialVersionUID = -7889272986162341211L;

		Sync(int count) {
			if (count <= 0) {
				throw new IllegalArgumentException("count must large than zero.");
			}
			setState(count);//这里设置state的值,也就是说,其实state的值是我们自己设的
		}
//重写这个方法,这个方法返回值小于0代表获取资源失败,反之为获取资源成功
		public int tryAcquireShared(int reduceCount) {
			for (;;) {
				int current = getState();
				int result = current - reduceCount;
				if (result < 0 || compareAndSetState(current, result)) {
					return result;
				}
			}
		}

		public boolean tryReleaseShared(int returnCount) {
			for (;;) {
				int current = getState();
				int result = current + returnCount;
				if (compareAndSetState(current, result)) {
					return true;
				}
			}
		}

	}

	@Override
	public void lock() {
		sync.acquireShared(1);
	}

	@Override
	public void lockInterruptibly() throws InterruptedException {
		sync.acquireSharedInterruptibly(1);
	}

	@Override
	public boolean tryLock() {
		return sync.tryAcquireShared(1) >= 0;
	}

	@Override
	public boolean tryLock(long time, TimeUnit unit) throws InterruptedException {
		return sync.tryAcquireSharedNanos(1, unit.toNanos(time));
	}

	@Override
	public void unlock() {
		sync.releaseShared(1);
	}

	@Override
	public Condition newCondition() {
		return null;
	}
}

实验类

public class TwinsLockTest {
	public static void main(String[] args){
		final Lock lock = new QueueSynchronizerTest();
		class Worker extends Thread {
			public void run() { 
					lock.lock();
					try {
						Thread.sleep(1000);
						System.out.println(Thread.currentThread().getName() + "," + Thread.currentThread());
						Thread.sleep(1000);
					} catch (Exception ex) {
						System.out.println("T1");
						ex.printStackTrace();
					} finally {
						lock.unlock();
					}
			}
		}
		for (int i = 0; i < 10; i++) {
			System.out.println("B" + i);
			Worker w = new Worker();
			w.start();
		}
	}
}

 控制台输出

B0
B1
B2
B3
B4
B5
B6
B7
B8

B9


Thread-1,Thread[Thread-1,5,main]

Thread-0,Thread[Thread-0,5,main]


Thread-2,Thread[Thread-2,5,main]

Thread-3,Thread[Thread-3,5,main]


Thread-5,Thread[Thread-5,5,main]

Thread-4,Thread[Thread-4,5,main]


Thread-6,Thread[Thread-6,5,main]

Thread-7,Thread[Thread-7,5,main]


Thread-9,Thread[Thread-9,5,main]
Thread-8,Thread[Thread-8,5,main]

我们可以看到,控制台隔一段时间才会显示两个线程,这是因为,我们限制了每次获取资源的,只能2个线程,当超过两个线程获取资源时,多出的线程会被放到队列里去

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值