Question

I am writing a simple multithreaded application that involves three threads: Thread-1, Thread-2 and main.

Thread-1 is a random number generator class that produces random doubles and feeds to Thread-2.

Thread-2 consumes the numbers to calculate the average .I have used PipedOutputStream that Thread-1 feeds with random numbers. Thread-2 uses PipedInputStream to eat up the random numbers.

The question is::

if the average exceeds 1E5 in Thread-2, I want to signal Thread-1 to stop producing numbers. I have a boolean flag in Thread-1 that needs to be turned on. How can I achieve this?

import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.io.PipedInputStream;
import java.io.PipedOutputStream;
import java.util.Random;

//

class NumGen extends Thread {

    PipedOutputStream pos;
    DataOutputStream dos;
    boolean isDone=false;

    public NumGen(PipedOutputStream pos){
        this.pos=pos;
        dos=new DataOutputStream(pos);
    }

    public void run(){
        while (!isDone){
            Random rand = new Random();
            try {
                dos.writeDouble(rand.nextDouble()+100.0);
            } catch (IOException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        }
    }
}

class RunningAvg extends Thread {

    PipedInputStream pis;
    DataInputStream dis;
    Double avg;
    int count;
    Double runningTotal;

    public RunningAvg(PipedInputStream pis){
        this.pis=pis;
        dis=new DataInputStream(pis);
            runningTotal=0.0;
    avg=0.0;
    }

    public void run(){
        try {
        while (dis.available()>0){
            count+=1;
            runningTotal+=dis.readDouble();
                avg=runningTotal/count;
                System.out.printf("The average in count no : %s is %s%n",count,avg);
                //if avg>1E5
                 //set NumGen.isDone=true
        }
            } catch (IOException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        }
    }


public class InterThreadComm {

    public static void main(String[] args){


    try {
        PipedOutputStream pos= new PipedOutputStream();
        PipedInputStream pis = new PipedInputStream(pos);
        NumGen ng = new NumGen(pos);
        RunningAvg ra = new RunningAvg(pis);
        ng.start();
        ra.start();
    } catch (IOException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    }
    }


}

PS: The code as it is runs forever without printing anything on console which I am yet to figure out why!!

Était-ce utile?

La solution

You could use AtomicBoolean and pass it to the both threads, Atomic types is accessable throw multithreading also thread safe.

first declare you flag isDone as AtomicBoolean

private AtomicBoolean isDone;

then declare one AtomicBoolean object and pass it to the both threads

PipedOutputStream pos= new PipedOutputStream();
PipedInputStream pis = new PipedInputStream(pos);
AtomicBoolean isDone = new AtomicBoolean();
NumGen ng = new NumGen(pos, isDone);
RunningAvg ra = new RunningAvg(pis, isDone);
ng.start();
ra.start();

finally once you want to stop generting numbers ask Thread-2 to set the isDone false.

Autres conseils

I would have the main() routine create a new AtomicBoolean object, and I would pass references to the object to the constructors of both Thread classes. The RunningAvg.run() method can set the AtomicBoolean, and the NumGen.run() method can examine it.

class NumGen extends Thread {
    ...
    AtomicBoolean isDone;

    public NumGen(PipedOutputStream pos, AtomicBoolean isDone){
        ...
        this.isDone = isDone;
    }

    public void run(){
        while (!isDone.get()){
            ...
        }
    }
}

class RunningAvg extends Thread {
    ...
    AtomicBoolean isDone;

    public RunningAvg(PipedInputStream pis, AtomicBoolean isDone){
        ...
        this.isDone = isDone;
    }

    public void run(){
        try {
        while (dis.available()>0){
            ...
            if (avg > 1E5) {
                isDone.set(true);
                ...
            }
        }
        ...
    }


public class InterThreadComm {

    public static void main(String[] args){

    try {
        ...
        AtomicBoolean isDone = new AtomicBoolean(false);
        NumGen ng = new NumGen(pos, isDone);
        RunningAvg ra = new RunningAvg(pis, isDone);
        ...
    }

You need to create a method that is accessible in both, using sychronized.

for ex:

   public synchronized boolean getDone()
   {
            return isDone;
   }

Otherwise you will have trouble keeping track of the variable between threads.

Here is a link that should help :http://docs.oracle.com/javase/tutorial/essential/concurrency/syncmeth.html

I would create a method called setIsDone() in NumGen.

public void setIsDone(boolean isDone) {
    this.isDone = isDone;
}

Your other thread can call this when it is time to for NumGen to finish.

Also, the general recommendation is that in most cases you should implement the Runnable interface instead of subclassing Thread directly, but that is just a rule of thumb not a hard and fast rule.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top