Java同步多线程的问题

时间:2018-05-05 08:49:36

标签: java multithreading

我只学习了wait()notify()notifyAll(),因此我必须使用此功能来控制程序。

这个程序有多个线程可以单独打印一些消息,但是在特定线程运行时我无法阻止其他线程。

我找到很多方法,但我完全不明白。我的代码如下。

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();
    }
}

我使用lock布尔变量在执行特定线程时让其他线程等待。

我真的想要正常结果哪些消息没有混合。

但我的结果是这样的。

  

LeftSideCar:接近......

     

frontCarVelocity:40:km / h方向:不要踩到左侧车道...

     

方向:RightSideCar:接近......降低速度......方向

     

:不要踩右车道... 80→70→60→50→40

如何仅使用wait()notify()notifyAll()进行修复?以上两个类是Sensor.java的子类,它具有lock布尔变量。

+一些用于理解的具体信息

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类是指具有可变传感器的汽车。 FrontCar等级是感知前车速度的传感器,而LeftRightCar等级是感知左右车辆移动的传感器。

因为它是实时系统,所以它是并发执行的,可以用java中的线程表示。

此外,Direction函数覆盖了如下函数。

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"));
        }
    }
}

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);
    }
}

2 个答案:

答案 0 :(得分:1)

代码中存在非常基本的缺陷,它与wait()和notify()方法的实现有关。在继续解决之前,让我们看看这些方法是如何实际工作的。

了解wait()和notify(): wait()notify()都是对象级API。它适用于当前正在处理该对象的线程。因此,等待列表维护在每个对象级别而不是线程级别。请考虑以下示例:

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){

            }
        }
    }
}

此示例包含两个主题t1t2以及一个对象example。我们为wait()对象调用了notify()example,因此如果t1执行wait()语句,它将被添加到对象example的等待列表中。其他线程也一样。

现有代码存在问题:有多项改进:

  1. 同步运行方法:不需要此同步,因为每个线程都有自己的运行实现,并且不会共享该线程对象。
  2. 布尔变量锁:直接布尔变量不是保持同步的好选择,因为当多个线程正在处理它时它们可能是一致性问题。
  3. wait()方法:这是实际问题所在。这里有两个对象,一个是LeftRightCar,另一个是FrontCar。因此,当为LeftRightCar调用wait()时,会在LeftRightCar对象的等待队列中添加线程。当它被FrontCar调用时,线程被添加到FrontCar对象的等待队列中。因此,实际的wait()notify()调用不同的对象无济于事。
  4. <强>解决方案:

    应该在某些公共对象上调用wait()notify()而不是这些类对象。因此,以下代码应该可以工作:

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

答案 1 :(得分:0)

  

我使用lock boolean变量来使其他线程等待   执行特定的线程。

如果您的锁被(&#34; this&#34;)守卫:

您的方法无论如何都是同步的,因此一次只有一个线程有机会执行该代码块。