简体   繁体   中英

How to make two threads wait and notify each other

I have to create two Threads which have to poll and object from a queue in 2 seconds intervals.

The first Thread poll and object then wait and notify the second one to poll the object from it's queue.

I read all about wait and notify but nothing works with me.

Any sugestions?

First thread:

public class SouthThread extends Thread {

private Queue<Car> q = new LinkedList<Car>();

public void CreateQueue() {

    Scanner input = new Scanner(System.in);

    for (int i = 0; i < 2; i++) {
        Car c = new Car();
        System.out.println("Enter registration number: ");
        String regNum = input.nextLine();
        c.setRegNum(regNum);
        q.offer(c);
    }
}

public int getQueueSize() {
    return q.size();
}

@Override
public void run() {
    while (q.size() != 0)
        try {
            while (q.size() != 0) {
                synchronized (this) {
                    System.out.print("The car with registration number: ");
                    System.out.print(q.poll().getRegNum());
                    System.out
                            .println(" have passed the bridge from the south side.");
                    this.wait(2000);
                    notify();

                }
            }
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
}

}

Second thread:

public class NorthThread extends Thread {
private Queue<Car> q = new LinkedList<Car>();

public void CreateQueue() {

    Scanner input = new Scanner(System.in);

    for (int i = 0; i < 2; i++) {
        Car c = new Car();
        System.out.println("Enter registration number: ");
        String regNum = input.nextLine();
        c.setRegNum(regNum);
        q.offer(c);
    }
}

public int getQueueSize() {
    return q.size();
}

@Override
public void run() {
    try {
        while (q.size() != 0) {
            synchronized (this) {
                System.out.print("The car with registration number: ");
                System.out.print(q.poll().getRegNum());
                System.out
                        .println(" have passed the bridge from the north side.");
                this.wait(2000);
                notify();
            }
        }
    } catch (InterruptedException e) {
        e.printStackTrace();
    }

}

}

Main Thread:

public class Main {

public static void main(String[] args) throws Exception {
    // TODO Auto-generated method stub

    SouthThread tSouthThread = new SouthThread();
    NorthThread tNorthThread = new NorthThread();

    tSouthThread.CreateQueue();
    tNorthThread.CreateQueue();

    System.out.println(tSouthThread.getQueueSize());

    tSouthThread.start();
    tNorthThread.start();


}

}

It seems that what you basically want to achieve is a system that alternates control between two independent units so that each of the units gets some time to process followed by a two second waiting period (or vice versa).

There are two main ways you could achieve this:

  1. Using a central control
  2. With autonomous communicating agents

The first approach is a bit easier. Here, you have a central "master" component which takes care of coordinating who gets the processing time and also implements the wait times. For that approach, the two independent units do not even have to be Threads:

public class South {
    private Queue<Car> q = new LinkedList<Car>();

    public void CreateQueue() { ... }

    public void poll() {
        System.out.print("The car with registration number: ");
        System.out.print(q.poll().getRegNum());
        System.out.println(" have passed the bridge from the South side.");
    }
}

public class North {
    private Queue<Car> q = new LinkedList<Car>();

    public void CreateQueue() { ... }

    public void poll() {
        System.out.print("The car with registration number: ");
        System.out.print(q.poll().getRegNum());
        System.out.println(" have passed the bridge from the North side.");
    }
}

// This is the "master" class
public class Main {
    public static void main(String[] args) {
        South south = new South();
        North north = new North();

        south.CreateQueue();
        north.CreateQueue();

        boolean done = false;
        while (!done) {
            try {
                Thread.sleep(2000);
            } (catch InterruptedException) { /* TODO */ }

            north.poll();

            try {
                Thread.sleep(2000);
            } (catch InterruptedException) { /* TODO */ }

            south.poll();
        }
    }
}

Note that North and South do not inherit from Thread here, ie, they are just plain old objects. (However, if your program is more complex and North/South are only one part of it, you might want to make Main(!) a separate thread and put the above while-loop inside the thread's run method, so that the rest of the program can run concurrently.)

In the second approach, you don't have such a central control component, but the both North and South run in their own separate threads. This then requires that they coordinate who's allowed to process by communicating with each other.

public class SouthThread extends Thread {
    protected Queue<Car> q = new LinkedList<Car>();
    protected North north;

    public void CreateQueue() { ... }
    public void poll() { ... }

    public void run() {
        boolean done = false;
        while (!done) {
            // wait two seconds
            try {
                Thread.sleep(2000);
            } (catch InterruptedException) { /* TODO */ }

            // process one element from the queue
            poll();

            // notify the other thread
            synchronized (north) {
                north.notifyAll();
            }

            // wait until the other thread notifies this one
            try {
                synchronized (this) {
                    wait();
                }
            } (catch InterruptedException) { /* TODO */ }
        }
    }
}

public class NorthThread extends Thread {
    protected Queue<Car> q = new LinkedList<Car>();
    protected South south;

    public void CreateQueue() { ... }
    public void poll() { ... }

    public void run() {
        boolean done = false;
        while (!done) {
            // wait two seconds
            try {
                Thread.sleep(2000);
            } (catch InterruptedException) { /* TODO */ }

            // process one element from the queue
            poll();

            // notify the other thread
            synchronized (south) {
                south.notifyAll();
            }

            // wait until the other thread notifies this one
            try {
                synchronized (this) {
                    wait();
                }
            } (catch InterruptedException) { /* TODO */ }
        }
    }
}

public class Main {
    public static void main(String[] args) throws Exception {
        SouthThread tSouthThread = new SouthThread();
        NorthThread tNorthThread = new NorthThread();

        tSouthThread.north = tNorthThread;
        tNorthThread.south = tSouthThread;

        tSouthThread.CreateQueue();
        tNorthThread.CreateQueue();

        tSouthThread.start();
        tNorthThread.start();    
    }
}

A more general remark: since both North and South seem to be doing basically the same, there's probably no need to implement them in two separate classes. Instead, it should be sufficient to have only one class that implements the desired functionality and instantiate it twice:

// We can combine the functionality of North and South 
// in a single class
public class NorthSouth {
    public void CreateQueue() { ... }
    public void poll() { ... }

    // etc.
}

public class Main {
    public static void main(String[] args) {
        NorthSouth north = new NorthSouth();
        NorthSouth south = new NorthSouth();

        north.CreateQueue();
        south.CreateQueue();

        // etc.
    }
}

wait and notify must refer to the same lock: When you call object.wait(2000) what you're saying is "I'm going to wait here for 2000 millis, or until someone else calls object.notify() where object refers to me "

I still don't completely understand what you want to achieve, but if you simply want two threads that concurrently do:

  1. Do something
  2. Wait 2 seconds
  3. GOTO 1

then you don't need wait/notify at all, you could get around using Thread.sleep() or potentially two instances of java.util.Timer .

But again, I'm not sure I understand correctly. :-(

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM