消费者 生产者

huangapple go评论79阅读模式
英文:

Consumer Producer

问题

ProdCom.java (驱动类)

import static java.lang.System.out;

public class ProdCom {
    static int full = 50;
    static int mutx = 0;
    static int empty = 0;
    static int currentSize = 0;

    public static void acquire() {
        while (mutx == 1);

        mutx++;
    }

    public static void release() {
        mutx--;
    }

    public static void main(String args[]) {
        Thread t = new Thread(new Producerr());
        Thread t1 = new Thread(new Consumerr());

        t.start();
        t1.start();
    }
}
Producerr.java

class Producerr implements Runnable {

    public void wwait() {
        while (ProdCom.currentSize >= ProdCom.full) {

        }
    }

    public void signal() {
        ProdCom.currentSize++;
    }

    public void run() {
        do {
            this.wwait();

            ProdCom.acquire();

            out.println("Num elements" + ProdCom.currentSize);
            out.println("producing!");

            ProdCom.release();
            this.signal();
        } while (true);
    }
}
Consumerr.java

class Consumerr implements Runnable {
    public void wwait() {
        while (ProdCom.currentSize <= 0) {
            out.println("inside consumer wait: ");
            out.println("number of elements: " + ProdCom.currentSize);
        }
    }

    public void signal() {
        ProdCom.currentSize--;
    }

    public void run() {
        do {

            this.wwait();
            ProdCom.acquire();

            out.println("Num elements" + ProdCom.currentSize);
            out.println("Consuming!");

            ProdCom.release();
            this.signal();
        } while (true);
    }
}

以上是我对生产者消费者问题的解决方案。驱动类 ProdCom 具有变量 fullemptymutx,用于控制生产者 t 和消费者 t1 对变量 currentSize 的访问(从而模拟缓冲区中当前项目的数量)。但是当我运行代码时,输出似乎表明 t1t 并没有轮流改变 currentSize,而是其中一个永远重复并被卡住了……我想知道为什么?谢谢。

英文:

ProdCom.java (driver class)

import static java.lang.System.out;


public class ProdCom{
    static int full = 50;
    static int mutx = 0;
    static int empty = 0;
    static int currentSize = 0;
   
    public static void acquire(){
        while (mutx == 1);
        
        mutx++;
        
    }
    
    public static void release(){
        mutx--;
    }
    
 
    public static void main(String args[]){
        Thread t = new Thread(new Producerr());
        Thread t1 = new Thread(new Consumerr());
                
        t.start();
        t1.start();
    }
   
    
}

Producerr.java

class Producerr implements Runnable{
        
        
        public void wwait(){
            while (ProdCom.currentSize &gt;= ProdCom.full){
                
            } 
            
        } public void signal(){
            ProdCom.currentSize++;
        }
        
        public void run(){
            do{
                this.wwait();
                
                ProdCom.acquire();
                
                out.println(&quot;Num elements&quot; + ProdCom.currentSize);
                out.println(&quot;producing!&quot;);
                
                ProdCom.release();
                this.signal();
            } while (true);
        }
    }

Consumerr.java

class Consumerr implements Runnable{
        public void wwait(){
            while (ProdCom.currentSize &lt;= 0){
                out.println(&quot;inside consumer wait: &quot;);
                out.println(&quot;number of elements: &quot; + ProdCom.currentSize);
            } 
            
        } public void signal(){
            ProdCom.currentSize--;
            
        }
        
      
        public void run(){
            do{
               
                this.wwait();
                ProdCom.acquire();
               
                out.println(&quot;Num elements&quot; + ProdCom.currentSize);
                out.println(&quot;Consuming!&quot;);
                
                ProdCom.release();
                this.signal();
            } while (true);
        } 
    }

Above is my solution to the consumer-producer problem. The driver class ProdCom has variables full, empty and mutx for controlling producer t and consumer t1's access to the variable currentSize (Thus simulating the current number of items in a buffer). But when I run the code, the output seems to indicate t1 and t aren't taking turns to change currentSize, instead one of them repeats forever and gets stuck...I'm wondering why? Thanks.

答案1

得分: 1

Java内存模型允许线程缓存变量的值,并且不同线程可以拥有不同的缓存。这意味着在acquire方法中,自旋锁很容易变成一个无限循环:执行acquire的线程可能会使用缓存的值mutx = 1,并且永远不会从主内存中读取更新后的值:

while (mutx == 1); // 即使另一个线程更改了mutx,这也会变成无限循环

另一个问题是++--运算符不是原子操作:它们会读取变量的值,修改它,然后写回。如果两个线程同时运行currentSize++currentSize--,可能会丢失其中一个操作。

您可以通过使用AtomicInteger对象及其方法来解决这些问题,而不是使用int。例如,在ProdCom中:

import java.util.concurrent.atomic.AtomicInteger;

public class ProdCom {
    static AtomicInteger currentSize = new AtomicInteger(0);
    static AtomicInteger mutx = new AtomicInteger(0);

    public static void acquire() {
        while (!mutx.compareAndSet(0, 1));
    }

    public static void release() {
        mutx.set(0);
    }
}
英文:

The Java memory models allows threads to cache the values of variables, and different threads to have different caches. This means that the spin lock in acquire easily becomes an infinite loop: the thread in acquire may use the cached value mutx = 1 and never read the updated value from main memory:

while (mutx == 1); // infinite loop even if another thread changes mutx

Another problem is that the ++ and -- operators are not atomic: they read the value of the variable, modify it, and write it back. If two threads run currentSize++ and currentSize-- at the same time it is possible one of them is lost.

You can fix these problems by using an AtomicInteger object and its methods instead of int, for example in ProdCom:

static AtomicInteger currentSize = new AtomicInteger(0);
static AtomicInteger mutx = new AtomicInteger(0);

public static void acquire() {
    while (!mutx.compareAndSet(0, 1));
}

public static void release() {
    mutx.set(0);
}

答案2

得分: 1

我稍微改进了你的代码,你会注意到许多Joni提到的概念都得到了考虑。

ProdCom.java

import java.lang.*;

public class ProdCom {
    static final int FULL = 50;
    static final int EMPTY = 0;

    static volatile int mutx = 0;
    static volatile int currentSize = 0;
    static Object lockObject = new Object();

    public static void acquire() {
        /* 由于mutx被定义为volatile,自旋锁会起作用,
           但是你可能要重新考虑这种方法。有更廉价的方法来加热房间 */
        while (mutx == 1);

        mutx++;

    }

    public static boolean isEmpty() {
        synchronized(lockObject) {
            if (currentSize <= EMPTY) return true;
            return false;
        }
    }

    public static boolean isFull() {
        synchronized(lockObject) {
            if (currentSize >= FULL) return true;
            return false;
        }
    }

    public static int getCurrentSize() {
        synchronized(lockObject) {
            return currentSize;
        }
    }

    public static void release() {
        mutx--;
    }

    public static void incCurrentSize() {
        synchronized(lockObject) {
            currentSize++;
        }
    }

    public static void decCurrentSize() {
        synchronized(lockObject) {
            currentSize--;
        }
    }

    public static void main(String args[]) {
        Thread t = new Thread(new Producerr());
        Thread t1 = new Thread(new Consumerr());

        t.start();
        t1.start();
    }
}

Consumerr.java

import java.lang.*;

class Consumerr implements Runnable {

    public void wwait() {
        while (ProdCom.isEmpty()) {
            System.out.println("inside consumer wait:");
            System.out.println("number of elements: " + ProdCom.getCurrentSize());
            try {
                /* 我们这里不会自旋 */
                Thread.sleep(50);
            } catch (Exception e) {
                /* 什么也不做 */
            }
        }
    }

    public void signal() {
        ProdCom.decCurrentSize();
    }

    public void run() {
        do {
            this.wwait();
            ProdCom.acquire();

            System.out.println("Num elements " + ProdCom.getCurrentSize());
            System.out.println("Consuming!");
            this.signal();

            ProdCom.release();
        } while (true);
    }
}

Producerr.java

import java.lang.*;

class Producerr implements Runnable {

    public void wwait() {
        while (ProdCom.isFull()) {
            try {
                Thread.sleep(50);
            } catch(Exception e) { /* 什么也不做 */ }
        }
    }

    public void signal() {
        ProdCom.incCurrentSize();
    }

    public void run() {
        do {
            this.wwait();

            ProdCom.acquire();

            System.out.println("Num elements : " + ProdCom.getCurrentSize());
            System.out.println("producing!");
            this.signal();

            ProdCom.release();
        } while (true);
    }
}
英文:

I've improved your code a bit, and you'll notice that many of the concepts mentioned by Joni are considered.

ProdCom.java

import java.lang.*;
public class ProdCom{
static final int FULL = 50;
static final int EMPTY = 0;
static volatile int mutx = 0;
static volatile int currentSize = 0;
static Object lockObject = new Object();
public static void acquire(){
/* since mutx is defined volatile, the spinlock works,
but you reconsider this approach. There are cheaper
methods of heating the room */
while (mutx == 1);
mutx++;
}
public static boolean isEmpty() {
synchronized(lockObject) {
if (currentSize &lt;= EMPTY) return true;
return false;
}
}
public static boolean isFull() {
synchronized(lockObject) {
if (currentSize &gt;= FULL) return true;
return false;
}
}
public static int getCurrentSize() {
synchronized(lockObject) {
return currentSize;
}
}
public static void release(){
mutx--;
}
public static void incCurrentSize()
{
synchronized(lockObject) {
currentSize++;
}
}
public static void decCurrentSize()
{
synchronized(lockObject) {
currentSize--;
}
}
public static void main(String args[]){
Thread t = new Thread(new Producerr());
Thread t1 = new Thread(new Consumerr());
t.start();
t1.start();
}
}

Consumerr.java

import java.lang.*;
class Consumerr implements Runnable {
public void wwait() {
while (ProdCom.isEmpty()){
System.out.println(&quot;inside consumer wait: &quot;);
System.out.println(&quot;number of elements: &quot; + ProdCom.getCurrentSize());
try {
/* we don&#39;t spinlock here */
Thread.sleep(50);
} catch (Exception e) {
/* do nothing */
}
} 
}
public void signal(){
ProdCom.decCurrentSize();
}
public void run(){
do{
this.wwait();
ProdCom.acquire();
System.out.println(&quot;Num elements &quot; + ProdCom.getCurrentSize());
System.out.println(&quot;Consuming!&quot;);
this.signal();
ProdCom.release();
} while (true);
} 
}

Producerr.java

import java.lang.*;
class Producerr implements Runnable {
public void wwait(){
while (ProdCom.isFull()){
try {
Thread.sleep(50);
} catch(Exception e) { /* do nothing */ }
} 
}
public void signal(){
ProdCom.incCurrentSize();
}
public void run(){
do {
this.wwait();
ProdCom.acquire();
System.out.println(&quot;Num elements : &quot; + ProdCom.getCurrentSize());
System.out.println(&quot;producing!&quot;);
this.signal();
ProdCom.release();
} while (true);
}
}

huangapple
  • 本文由 发表于 2020年8月17日 18:07:21
  • 转载请务必保留本文链接:https://go.coder-hub.com/63448699.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定