问题描述
我正在尝试通过信号量来编写生产者-消费者问题的解决方案。 下面是我编写的代码,在执行时会产生一个数字而卡住。
我已经检查了信号量的分配,看起来还不错。 调用获取和释放方法的顺序看起来也正确。
public class Q {
int n;
Semaphore consumerSem = new Semaphore(0);
Semaphore producerSem = new Semaphore(1);
synchronized void get(){
try {
consumerSem.acquire();
} catch (InterruptedException e) {
e.printstacktrace();
}
System.out.println("Got Data : " + n);
producerSem.release();
}
synchronized void put(int n){
try {
producerSem.acquire();
} catch (InterruptedException e) {
e.printstacktrace();
}
System.out.println("Putting Data : " + n);
this.n=n;
consumerSem.release();
}
}
public class Producer implements Runnable{
Q q;
Producer(Q q){
this.q = q;
}
@Override
public void run() {
for (int i=0; i<20;i++){
q.put(i);
}
}
}
public class Consumer implements Runnable{
Q q;
Consumer(Q q){
this.q = q;
}
@Override
public void run() {
for (int i =0;i<20;i++){
q.get();
}
}
}
public class PCRun {
public static void main(String[] args) {
Q q = new Q();
new Thread(new Producer(q),"Producer").start();
new Thread(new Consumer(q),"Consumer").start();
}
}
解决方法
您已经制作了get
和put
synchronized
。因此,生产者进入,锁定q
,使用producerSem
的一个许可并在下一个put
调用时阻塞。不幸的是,q
仍然被生产者锁定,因此消费者将无法输入get
。要解决此问题,请同时删除两个synchronized
。
现在要在n
上同步访问,仅在访问{em> synchronized
的地方使用n
,而不是同时使用两种方法。
int n;
final Semaphore consumerSem = new Semaphore(0);
final Semaphore producerSem = new Semaphore(1);
void get() {
try {
consumerSem.acquire();
} catch (InterruptedException e) {
e.printStackTrace();
}
synchronized (this) {
System.out.println("Got Data : " + n);
}
producerSem.release();
}
void put(int n) {
try {
producerSem.acquire();
} catch (InterruptedException e) {
e.printStackTrace();
}
synchronized (this) { // invariant print + write,atomic
System.out.println("Putting Data : " + n);
this.n = n;
}
consumerSem.release();
}
,
不是使用2个信号量,而是仅使用1个。n
的值最终将在2个线程之间共享,因此它是唯一需要同步的东西,因为信号量本质上是线程安全的。
public static class Q {
int n;
Semaphore available = new Semaphore(0);
void get() throws InterruptedException {
available.acquire();
synchronized (this) {
System.out.printf("Get %s\n",n));
}
}
void put(int n){
available.release();
synchronized (this) {
System.out.printf("Put %s\n",n);
this.n = n;
}
}
}