【问题】
有n个桃子, 猴子A每次固定摘2个,猴子B每次固定摘3个,这2只猴子不断摘桃子直到剩余桃子数量不足以摘(必须满足摘桃个数);
【1】 使用AtomicInteger(推荐)
1)利用 原子类的CAS原子函数(乐观锁)实现并发控制访问;
2)推荐; 乐观锁实现,代码简单,性能高;
public class AtomicIntegerTest {public static void main(String[] args) {ExecutorService executorService = Executors.newFixedThreadPool(2);Object lock = new Object();AtomicInteger cap = new AtomicInteger(103);executorService.execute(new Task(cap, 2));executorService.execute(new Task(cap, 3));executorService.shutdown();}private static class Task implements Runnable {private AtomicInteger cap;private int consumeSize;private int takeCount = 0;Task(AtomicInteger cap, int consumeSize) {this.cap = cap;this.consumeSize = consumeSize;}@Overridepublic void run() {while (take()) ;PrintUtils.print(Thread.currentThread().getName() + "#" + this);}boolean take() {if (cap.addAndGet(-consumeSize) >= 0) {takeCount++;return true;}return false;}@Overridepublic String toString() {return "Task{" +"consumeSize=" + consumeSize +", takeCount=" + takeCount +'}';}}
}
【2】使用synchronized同步代码块
监视器锁内存结构:
1)用户线程访问Synchronized同步代码块获取锁流程
2)代码示例
public class SynchronizedTest {private static volatile Integer CAPACITY = 14;public static void main(String[] args) {ExecutorService executorService = Executors.newFixedThreadPool(2);Object lock = new Object();executorService.execute(new Task( 2, lock));executorService.execute(new Task( 3, lock));executorService.shutdown();}static class Task implements Runnable {private int consumeSize;private Object lock;private int takeCount = 0;Task(int consumeSize, Object lock) {this.consumeSize = consumeSize;this.lock = lock;}@Overridepublic void run() {while(take());PrintUtils.print(Thread.currentThread().getName() + "#" + this);}boolean take() {synchronized (lock) {if (CAPACITY >= consumeSize) {CAPACITY -= consumeSize;takeCount++;return true;}return false;}}@Overridepublic String toString() {return "Task{" +"consumeSize=" + consumeSize +", takeCount=" + takeCount +'}';}}
}
2024-06-09 10:42:56.989 pool-1-thread-1#Task{consumeSize=2, takeCount=4}
2024-06-09 10:42:56.989 pool-1-thread-2#Task{consumeSize=3, takeCount=2}
【3】使用可重入锁ReentrantLock
public class ReentrantLockTest {private static volatile Integer CAPACITY = 103;public static void main(String[] args) {ExecutorService executorService = Executors.newFixedThreadPool(2);ReentrantLock reentrantLock = new ReentrantLock();executorService.execute(new Task(2, reentrantLock));executorService.execute(new Task(3, reentrantLock));executorService.shutdown();}static class Task implements Runnable {private int consumeSize;private ReentrantLock reentrantLock;private int takeCount = 0;Task(int consumeSize, ReentrantLock reentrantLock) {this.consumeSize = consumeSize;this.reentrantLock = reentrantLock;}@Overridepublic void run() {while (take()) ;PrintUtils.print(Thread.currentThread().getName() + "#" + this);}boolean take() {reentrantLock.lock(); // 加锁try {if (CAPACITY >= consumeSize) {CAPACITY -= consumeSize;takeCount++;return true;}return false;} finally {reentrantLock.unlock(); // 解锁}}@Overridepublic String toString() {return "Task{" +"consumeSize=" + consumeSize +", takeCount=" + takeCount +'}';}}
}
【4】 使用信号量Semaphore实现
semaphore.acquire()#信号量个数减1 和 release()#信号量个数加1 ;如信号量个数等于0,则 acquire() 阻塞;
public class SemaphoreTest {private static volatile Integer CAPACITY = 103;public static void main(String[] args) {ExecutorService executorService = Executors.newFixedThreadPool(2);Semaphore semaphore = new Semaphore(1);// 信号量数量初始为1 executorService.execute(new Task(2, semaphore));executorService.execute(new Task(3, semaphore));executorService.shutdown();}static class Task implements Runnable {private int consumeSize;private Semaphore semaphore;private int takeCount = 0;Task(int consumeSize, Semaphore semaphore) {this.consumeSize = consumeSize;this.semaphore = semaphore;}@Overridepublic void run() {while (take()) ;PrintUtils.print(Thread.currentThread().getName() + "#" + this);}boolean take() {// 获取信号量(信号数量减1)try {semaphore.acquire();if (CAPACITY >= consumeSize) {CAPACITY -= consumeSize;takeCount++;return true;}return false;} catch (Exception e) {throw new RuntimeException(e);} finally {semaphore.release();}}@Overridepublic String toString() {return "Task{" +"consumeSize=" + consumeSize +", takeCount=" + takeCount +'}';}}
}
2024-06-09 14:20:18.509 pool-1-thread-2#Task{consumeSize=3, takeCount=5}
2024-06-09 14:20:18.509 pool-1-thread-1#Task{consumeSize=2, takeCount=44}