Потоковая программа Java работает в Eclipse, но не в терминале / командной строке

#java #eclipse

#java #eclipse

Вопрос:

Этот код отлично работает в eclipse, но не в командной строке (или терминале). Я был бы очень признателен за любую помощь, поскольку я понятия не имею, почему это не работает. Она выполняется полностью в Eclipse, но зависает во время выполнения в командной строке.

Класс Producer генерирует случайные удвоения и вызывает add(), в то время как класс Consumer вызывает pop(); оба вызывают эти 1 000 000 раз.

Buffer.java

 public class Buffer{

private double[] buf;
private int next = 0;
private int start = 0;
private int semaphore = 1;
private boolean isFull = false;
private boolean isEmpty = true;

public static void main(String[] args) {
    Buffer pcbuf = new Buffer(1000);
    Thread prod = new Thread (new Producer(pcbuf));
    Thread cons = new Thread (new Consumer(pcbuf));
    prod.start();
    cons.start();
}

public Buffer(int size){
    buf = new double[size];
}

private synchronized void bwait(){
    while(semaphore <= 0){}
    semaphore--;
}

private void bnotify(){
    semaphore  ;
}

public void add(double toAdd){
    boolean hasAdded = false;
    while(!hasAdded){
        if(!isFull){
            bwait();
            buf[next] = toAdd;
            next=(next 1)%buf.length;
            if(next == start){
                isFull = true;
            }
            isEmpty = false;
            hasAdded = true;
            bnotify();
        }
    }
}

public double pop(){
    boolean hasPopped = false;
    double toReturn = 0.0;
    while(!hasPopped){
        if(!isEmpty){
            bwait();
            toReturn = buf[start];
            start=(start 1)%buf.length;
            if(start == next){
                isEmpty = true;
            }
            isFull = false;
            hasPopped = true;
            bnotify();
        }
    }
    return toReturn;
}
}
  

Producer.java

 import java.text.DecimalFormat;
import java.util.Random;

public class Producer extends Thread{

private Buffer b;
private double bufferValueCounter = 0.0;
private int numProduced = 0;

public Producer(Buffer b){
    this.b = b;
}

public void run() {
    Random r = new Random();
    DecimalFormat df = new DecimalFormat("#,###");
    while (numProduced < 1000000){
        double toAdd = r.nextDouble() * 100.0;
        b.add(toAdd);
        bufferValueCounter =toAdd;
        numProduced  ;
        if(numProduced%100000==0){
            System.out.println("Producer: Generated "   df.format(numProduced)   " items, Cumulative value of generated items = "   bufferValueCounter);
        }
    }
    System.out.println("Producer: Finished generating 1,000,000 items");
}   
}
  

Consumer.java

 import java.text.DecimalFormat;

public class Consumer extends Thread{

private Buffer b;
private double bufferValueCounter = 0.0;
private int numConsumed = 0;

public Consumer(Buffer b){
    this.b = b;
}

public void run(){
    DecimalFormat df = new DecimalFormat("#,###");
    while(numConsumed < 1000000){
        double popped = b.pop();
        bufferValueCounter  = popped;
        numConsumed  ;
        if(numConsumed%100000==0){
            System.out.println("Consumer: Consumed  "   df.format(numConsumed)   " items, Cumulative value of consumed items  = "   bufferValueCounter);
        }
    }
    System.out.println("Consumer: Finished consuming 1,000,000 items");
}
}
  

Комментарии:

1. Я тоже понятия не имею, потому что вы не определили «не работает». Ошибка компиляции, исключение во время выполнения, логическая ошибка?

2. Мы могли бы использовать magic 8-ball, но я сомневаюсь, что это сильно поможет.

3. Честно говоря, вы можете захотеть ознакомиться с руководствами по потоковой обработке Java. download.oracle.com/javase/tutorial/essential/concurrency/… Тот факт, что этот код работает в eclipse, не обязательно является чем-то большим, чем удачей.

4. чтобы прояснить / перефразировать то, что сказал @Brian Roach, тот факт, что это работает где угодно, является исключительно удачей. вы не использовали никаких допустимых механизмов синхронизации потоков, поэтому поведение ваших программ полностью не определено.

5. нет, bwait недопустимо. пожалуйста, немного почитайте о потоковой передаче и видимости изменений. за пределами любых «действий синхронизации потоков» изменения, сделанные одним потоком, не обязательно должны быть видны любому другому потоку. таким образом, производитель и потребитель могут каждый изменять значение «семафора» сколько угодно и никогда не видеть изменений друг друга (по крайней мере, это одно из возможных действий).

Ответ №1:

Вам необходимо синхронизировать методы pop и add. Я думаю, что это должно устранить проблему.