【问题】
有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;
}
@Override
public void run() {
while (take()) ;
PrintUtils.print(Thread.currentThread().getName() + "#" + this);
}
boolean take() {
if (cap.addAndGet(-consumeSize) >= 0) {
takeCount++;
return true;
}
return false;
}
@Override
public 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;
}
@Override
public void run() {
while(take());
PrintUtils.print(Thread.currentThread().getName() + "#" + this);
}
boolean take() {
synchronized (lock) {
if (CAPACITY >= consumeSize) {
CAPACITY -= consumeSize;
takeCount++;
return true;
}
return false;
}
}
@Override
public 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;
}
@Override
public 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(); // 解锁
}
}
@Override
public 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;
}
@Override
public 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();
}
}
@Override
public 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}