1.提出问题
在上个博客中,使用等待唤醒机制,可以达到一进一出的效果,可是实际的开发中,不止两个线程,一般都会多个线程,那么此时会出现什么问题???
class Resource {
private String name;
private int count = 1;
private boolean flag = false;
public synchronized void set(String name) {
if (flag) {
try {
wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
this.name = name + "......" + count++;
System.out.println(Thread.currentThread().getName() + "生产者...." + this.name);
flag = true;
notify();
}
public synchronized void out(){
if(!flag){
try {
wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println(Thread.currentThread().getName()+"消费者......"+this.name);
flag=false;
notify();
}
}
class Producer implements Runnable{
private Resource resource;
public Producer(Resource resource) {
this.resource = resource;
}
@Override
public void run() {
while (true){
resource.set("+商品+");
}
}
}
class Consumer implements Runnable{
private Resource resource;
public Consumer (Resource resource) {
this.resource = resource;
}
@Override
public void run() {
while (true){
resource.out();
}
}
}
public class ProducerConsumerDemo {
public static void main(String[] args) {
Resource resource = new Resource();
Thread t1 = new Thread(new Producer(resource));
Thread t2 = new Thread(new Producer(resource));
Thread t3 = new Thread(new Consumer(resource));
Thread t4 = new Thread(new Consumer(resource));
t1.start();
t2.start();
t3.start();
t4.start();
}
}

2.原因分析


可能有个疑问,t2由于判断过标记,所以唤醒以后不再判断标记,直接执行if语句块中的内容,那么为什么换成while以后就会回去判断这个标记了呢?
这跟while语法有关,下面补充一下if和while的本质区别:
现在将if改成while后,会出现什么问题?
原因在于notify()只会唤醒本方的线程,应该唤醒对方的线程。所以改为notifyAll()
最终Resource程序为:
class Resource {
private String name;
private int count = 1;
private boolean flag = false;
public synchronized void set(String name) {
while (flag) {
try { wait();} catch (InterruptedException e){ e.printStackTrace(); }
}
this.name = name + "......" + count++;
System.out.println(Thread.currentThread().getName() + "生产者...." + this.name);
flag = true;
notifyAll();
}
public synchronized void out(){
while (!flag){
try { wait();} catch (InterruptedException e){ e.printStackTrace(); }
}
System.out.println(Thread.currentThread().getName()+"消费者......"+this.name);
flag=false;
notifyAll();
}
}

4.使用Lock锁改进上述程序




下面的代码是将上面的代码完全替换成lock的形式:
class Resource {
private String name;
private int count = 1;
private boolean flag = false;
private Lock lock = new ReentrantLock();
private Condition condition = lock.newCondition();
public void set(String name) throws InterruptedException {
lock.lock();
try{
while (flag) {
condition.await();
}
this.name = name + "......" + count++;
System.out.println(Thread.currentThread().getName() + "生产者...." + this.name);
flag = true;
condition.signalAll();
}finally {
lock.unlock();
}
}
public void out() throws InterruptedException {
lock.lock();
try {
while (!flag){
condition.await();
}
System.out.println(Thread.currentThread().getName()+"消费者......"+this.name);
condition.signalAll();
flag=false;
} finally {
lock.unlock();
}
}
}
class Producer implements Runnable{
private Resource resource;
public Producer(Resource resource) {
this.resource = resource;
}
@Override
public void run() {
while (true){
try {
resource.set("+商品+");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
class Consumer implements Runnable{
private Resource resource;
public Consumer (Resource resource) {
this.resource = resource;
}
@Override
public void run() {
while (true){
try {
resource.out();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
public class ProducerConsumerDemo {
public static void main(String[] args) {
Resource resource = new Resource();
Thread t1 = new Thread(new Producer(resource));
Thread t2 = new Thread(new Producer(resource));
Thread t3 = new Thread(new Consumer(resource));
Thread t4 = new Thread(new Consumer(resource));
t1.start();
t2.start();
t3.start();
t4.start();
}
}
但是还是唤醒了本方的线程,现在只想唤醒对方的线程:
class Resource {
private String name;
private int count = 1;
private boolean flag = false;
private Lock lock = new ReentrantLock();
private Condition condition_producer = lock.newCondition();
private Condition condition_consumer = lock.newCondition();
public void set(String name) throws InterruptedException {
lock.lock();
try{
while (flag) {
condition_producer.await();
}
this.name = name + "......" + count++;
System.out.println(Thread.currentThread().getName() + "生产者...." + this.name);
flag = true;
condition_consumer.signalAll();
}finally {
lock.unlock();
}
}
public void out() throws InterruptedException {
lock.lock();
try {
while (!flag){
condition_consumer.await();
}
System.out.println(Thread.currentThread().getName()+"消费者......"+this.name);
condition_producer.signalAll();
flag=false;
} finally {
lock.unlock();
}
}
}
class Producer implements Runnable{
private Resource resource;
public Producer(Resource resource) {
this.resource = resource;
}
@Override
public void run() {
while (true){
try {
resource.set("+商品+");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
class Consumer implements Runnable{
private Resource resource;
public Consumer (Resource resource) {
this.resource = resource;
}
@Override
public void run() {
while (true){
try {
resource.out();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
public class ProducerConsumerDemo {
public static void main(String[] args) {
Resource resource = new Resource();
Thread t1 = new Thread(new Producer(resource));
Thread t2 = new Thread(new Producer(resource));
Thread t3 = new Thread(new Consumer(resource));
Thread t4 = new Thread(new Consumer(resource));
t1.start();
t2.start();
t3.start();
t4.start();
}
}
来源:CSDN
作者:@追风筝的人
链接:https://blog.csdn.net/qq_42764468/article/details/103449976