molamola
molamola

Reputation: 269

Java synchronized problems of multiple threads

I learned only wait() and notify() or notifyAll(), so I have to use this function to control of programs.

This program has multiple threads which print set of some message individually, but I cannot block other thread while specific thread is running.

I find lots of way to do but I totally didn't understand. My code is below.

LeftRightCar.java:

public synchronized void run(){
    try{
        while(lock) wait();
        lock=true;
        System.out.println("LeftSideCar: "+left);
        state="Left";
        Direction();
        System.out.println("RightSideCar: "+right);
        state="Right";
        Direction();
        notifyAll();
        lock=false;
    }catch(InterruptedException e){
        e.printStackTrace();
    }
}

FrontCar.java:

public synchronized void run(){
    try{
        while(lock) wait();
        lock=true;
        System.out.println("frontCarVelocity: "+frontCarSpeed+": km/h");
        Direction();
        notifyAll();
        lock=false;
    }catch(InterruptedException e){
        e.printStackTrace();
    }
}

I'm using lock boolean variable to make other thread wait during execution of specific thread.

I really want to normal result which messages are not mixed.

But my result is like this.

LeftSideCar: Approaching...

frontCarVelocity: 40: km/h Direction : Do not step on left lane...

Direction : RightSideCar: Approaching... Decrease velocity...Direction

: Do not step on right lane... 80 → 70 → 60 → 50 → 40

How can I fix it using only wait(), notify() or notifyAll()? Above two classes are children class of Sensor.java which has lock boolean variable.

+some specific information for understanding

public class AutonomousCar {
public static void main(String[] args){
    FrontCar f=new FrontCar();
    LeftRightCar lr=new LeftRightCar();
    Thread Car[]={new Thread(f),new Thread(lr)};
    Car[0].start();
    Car[1].start();
}

AutonomousCar class means car which has variable sensors. FrontCar class is a sensor that sense the speed of front car and LeftRightCar class is a sensor that sense the moving of left and right car.

Because it is real-time system, it is concurrently executed which can be represented by threads in java.

Furthermore, Direction function is overriding function like below.

Direction of LeftRightCar.java

public void Direction(){
    System.out.print("Direction : ");
    if(state.equals("Left")){
        if(left.equals("None")) System.out.println(message.get("None"));
        else if(left.equals("Approaching...")) System.out.println(message.get("Approaching-L"));
        else if(left.equals("Too close...")){
            System.out.println(message.get("Close-L"));
            isLeftClose=true;
        }
    }
    else if(state.equals("Right")){
        if(right.equals("None")) System.out.println(message.get("None"));
        else if(right.equals("Approaching...")) System.out.println(message.get("Approaching-R"));
        else if(right.equals("Too close...")){
            if(!isLeftClose) System.out.println(message.get("Close-R"));
            else System.out.println(message.get("Close-LR"));
        }
    }
}

Direction of FrontCar.java

public void Direction(){
    System.out.print("Direction : ");
    if(frontCarSpeed==100){
        System.out.println(message.get("S"));
    }
    else if(speed<=frontCarSpeed){
        System.out.print(message.get("I"));
        while(speed<frontCarSpeed){
            System.out.print(speed+" → ");
            speed+=10;
        }
        System.out.println(speed);
    }
    else if(speed>frontCarSpeed){
        System.out.print(message.get("D"));
        while(speed>frontCarSpeed){
            System.out.print(speed+" → ");
            speed-=10;
        }
        System.out.println(speed);
    }
}

Upvotes: 3

Views: 1306

Answers (2)

Amber Beriwal
Amber Beriwal

Reputation: 1598

There is very basic flaw in the code which is related to implementation of wait() and notify() methods. Let's see how these methods actually works before proceeding to solution.

Understanding wait() and notify(): Both wait() and notify() are object level APIs. It applies on threads that is currently working on the object. So, waiting lists are maintained at each object level instead of thread level. Consider below example:

public class Example{
  int counter = 0;

  synchronized void printCounter() throws Exception{
    notify();
    System.out.println(Thread.currentThread().getName() + "-->" + (counter++));
    wait();
  }

  public static void main(String[] args){
      Example example = new Example();
      Thread t1 = new MyThread(example);
      t1.setName("MyThread-1");
      Thread t2 = new MyThread(example);
      t2.setName("MyThread-2");
      t1.start();
      t2.start();
  }
}

class MyThread extends Thread{
    private Example obj = null;

    MyThread(Example obj){
        this.obj = obj;
    }

    public void run(){
        while(true){
            try{
                obj.printCounter();
                Thread.sleep(200);
            }catch(Exception ex){

            }
        }
    }
}

This example has two threads, t1 and t2 and one object example. We have called wait() and notify() for example object thus if t1 executes wait() statement, it will be added in waiting list for object example. Same goes with other threads.

Problem with existing code: There are multiple improvements to be made:

  1. Synchronization over run method: This synchronization won't be required as each thread will have its own implementation for run and that thread object won't be shared.
  2. boolean variable lock: Direct boolean variables are not a good option to maintain synchronization as their could be consistency issues when multiple threads are working on it.
  3. wait() method: This is where the actual problem lies. Here we have two objects, one of LeftRightCar and another of FrontCar. So, when wait() is called for LeftRightCar, thread is added in waiting queue of LeftRightCar object. And when it is called for FrontCar, thread is added in waiting queue of FrontCar object. So, in actual wait() and notify() calls for different objects won't help.

Solution:

The wait() and notify() should be called on some common object instead of these classes object. So, following code should work:

//lock is an instance of Object now, NOT a boolean variable
public void run(){ 
  synchronized(lock){
    lock.notifyAll();
    ...
    ...
    lock.wait();
  }
}

Upvotes: 1

Yati Sawhney
Yati Sawhney

Reputation: 1402

I'm using lock boolean variable to make other thread wait during execution of specific thread.

if your lock is guarded by ("this"):

Your methods are anyways synchronized, So only one thread will get a chance to execute that block of code at a time.

Upvotes: 0

Related Questions