带队列的信号量
Semaphore with queue
public class SemaphoreWithQueues implements Semaphore {
private List<Object> queue;
private AtomicInteger current = new AtomicInteger(0);
private int permits;
public SemaphoreWithQueues(int permits) {
this.permits = permits;
this.queue = Collections.synchronizedList(new LinkedList<>());
}
@Override
public void enter() throws InterruptedException {
if (current.get() < permits) {
current.incrementAndGet();
} else {
Object block = new Object();
synchronized (block) {
queue.add(block);
block.wait();
current.incrementAndGet();
}
}
}
@Override
public void leave() {
if(queue.size() != 0) {
Object block = queue.get(0);
queue.remove(0);
synchronized (block) {
block.notify(); //Unblock quenue
}
}
current.decrementAndGet();
//current lessen and current thread have time come in block if(...)
// in enter() faster then another thread increased current
}
}
> The program usually output:
>
> 1 1 2 2 1 1 2 2 1 2
**Where run() of both threads is almost the same, such as:**
public void run(){
for (int i = 0; i <5; i++) {
try {
semaphore.enter();
} catch (InterruptedException e) {
System.err.println(e);
}
System.out.println(2);
semaphore.leave();
}
}
有 2 个线程使用此信号量。当1个线程增加queue时,第二个在等待,问题是如果我们从quene中提取对象并解除阻塞,那么线程完成 leave() 更快地启动 enter() 并再次递增 counter,同时唤醒线程还增加了 counter,current = 2,列表为空。
抱歉英语不好
代码中有很多问题。
- 同步:应为可共享的内容进行同步
资源。为什么它是为一个只具有范围的本地对象完成的
那个方法。
Object block = new Object();
synchronized (block) {
- current和queue都是独立的属性,应该是
一起同步。
现在让我们来点如果你真的想用Queue创建一个信号量。您不需要所有这些逻辑。您可以使用现有的 Java class 例如阻塞队列。这是实现
class SemaphoreWithQueues implements Semaphore{
private BlockingQueue<Integer> queue;
public SemaphoreWithQueues(int permits) {
if(queue == null){
queue = new ArrayBlockingQueue<>(permits);
}
}
public void enter() {
queue.offer(1);
System.out.println(Thread.currentThread().getName() + " got a permit.");
}
public void leave() throws InterruptedException {
queue.take();
System.out.println(Thread.currentThread().getName() + " left the permit.");
}
}
和任务使用信号量
class Task implements Runnable {
private SemaphoreWithQueues semaphore;
public Task(SemaphoreWithQueues semaphore){
this.semaphore = semaphore;
}
public void run(){
for (int i = 0; i <5; i++) {
semaphore.enter();
try {
semaphore.leave();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
public class Main {
public static void main(String[] args) {
SemaphoreWithQueues semaphoreWithQueues = new SemaphoreWithQueues(5);
Thread th1 = new Thread(new Task(semaphoreWithQueues));
Thread th2 = new Thread(new Task(semaphoreWithQueues));
Thread th3 = new Thread(new Task(semaphoreWithQueues));
th1.start();
th2.start();
th3.start();
}
}
但我个人不喜欢使用队列来创建信号量,因为它通过在队列中创建元素来浪费不必要的内存。尽管如此,您可以使用等待和通知机制的许可使用单个可共享对象创建信号量。您可以尝试使用这种方法。如果你愿意。
public class SemaphoreWithQueues implements Semaphore {
private List<Object> queue;
private AtomicInteger current = new AtomicInteger(0);
private int permits;
public SemaphoreWithQueues(int permits) {
this.permits = permits;
this.queue = Collections.synchronizedList(new LinkedList<>());
}
@Override
public void enter() throws InterruptedException {
if (current.get() < permits) {
current.incrementAndGet();
} else {
Object block = new Object();
synchronized (block) {
queue.add(block);
block.wait();
current.incrementAndGet();
}
}
}
@Override
public void leave() {
if(queue.size() != 0) {
Object block = queue.get(0);
queue.remove(0);
synchronized (block) {
block.notify(); //Unblock quenue
}
}
current.decrementAndGet();
//current lessen and current thread have time come in block if(...)
// in enter() faster then another thread increased current
}
}
> The program usually output:
>
> 1 1 2 2 1 1 2 2 1 2
**Where run() of both threads is almost the same, such as:**
public void run(){
for (int i = 0; i <5; i++) {
try {
semaphore.enter();
} catch (InterruptedException e) {
System.err.println(e);
}
System.out.println(2);
semaphore.leave();
}
}
有 2 个线程使用此信号量。当1个线程增加queue时,第二个在等待,问题是如果我们从quene中提取对象并解除阻塞,那么线程完成 leave() 更快地启动 enter() 并再次递增 counter,同时唤醒线程还增加了 counter,current = 2,列表为空。
抱歉英语不好
代码中有很多问题。
- 同步:应为可共享的内容进行同步 资源。为什么它是为一个只具有范围的本地对象完成的 那个方法。
Object block = new Object(); synchronized (block) {
- current和queue都是独立的属性,应该是 一起同步。
现在让我们来点如果你真的想用Queue创建一个信号量。您不需要所有这些逻辑。您可以使用现有的 Java class 例如阻塞队列。这是实现
class SemaphoreWithQueues implements Semaphore{
private BlockingQueue<Integer> queue;
public SemaphoreWithQueues(int permits) {
if(queue == null){
queue = new ArrayBlockingQueue<>(permits);
}
}
public void enter() {
queue.offer(1);
System.out.println(Thread.currentThread().getName() + " got a permit.");
}
public void leave() throws InterruptedException {
queue.take();
System.out.println(Thread.currentThread().getName() + " left the permit.");
}
}
和任务使用信号量
class Task implements Runnable {
private SemaphoreWithQueues semaphore;
public Task(SemaphoreWithQueues semaphore){
this.semaphore = semaphore;
}
public void run(){
for (int i = 0; i <5; i++) {
semaphore.enter();
try {
semaphore.leave();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
public class Main {
public static void main(String[] args) {
SemaphoreWithQueues semaphoreWithQueues = new SemaphoreWithQueues(5);
Thread th1 = new Thread(new Task(semaphoreWithQueues));
Thread th2 = new Thread(new Task(semaphoreWithQueues));
Thread th3 = new Thread(new Task(semaphoreWithQueues));
th1.start();
th2.start();
th3.start();
}
}
但我个人不喜欢使用队列来创建信号量,因为它通过在队列中创建元素来浪费不必要的内存。尽管如此,您可以使用等待和通知机制的许可使用单个可共享对象创建信号量。您可以尝试使用这种方法。如果你愿意。