2017-01-26 39 views
1

У меня есть объект Rotor, у которого есть цель Speed ​​и currentSpeed. Каждый пытается изменить его currentSpeed, чтобы соответствовать набору goalSpeed. У меня 4 из этих роторов, работающих с 4 отдельными потоками. Периодически каждый контроллер получает новую контрольную точку.Синхронизировано между экземплярами объекта

Когда я пытаюсь в каждом Роторе изменить его currentSpeed, я не могу превышать сумму всей текущей скорости ротора, чтобы превысить значение X. sum (currentSpeed ​​(Rotor1) + ... + currentSpeed ​​(Rotor2))!> X.

Вот моя проблема: когда я проверяю, могу ли увеличить текущую скорость ротора, я делаю инструкцию if на сумма скоростей. Однако возможно, что сразу после этой проверки, поскольку каждый ротор представляет собой отдельный поток, который другой изменяет свое значение. Поэтому моя проверка в другом потоке уже недействительна. Как я могу убедиться, что, пока я нахожусь в методе setNewSpeed ​​() одного ротора, никакой другой ротор не изменит его текущую скорость?

class Rotor implements Runnable { 
    private int id; 
    private int goalSpeed; 
    private int currentSpeed; 
    private Controller controller; 
    private int Y; 
    private int failedAttempts; 
    private int successAttempts; 
    private int maxSpeed; 

    public int getSuccessAttempts() { 
     return successAttempts; 
    } 

    public void setSuccessAttempts(int successAttempts) { 
     this.successAttempts = successAttempts; 
    } 

    public int getMaxSpeed() { 
     return maxSpeed; 
    } 

    public void setMaxSpeed(int maxSpeed) { 
     this.maxSpeed = maxSpeed; 
    } 

    public int getFailedAttempts() { 
     return failedAttempts; 
    } 

    public Rotor(Controller c, int Y, int id){ 
     this.controller = c; 
     this.Y = Y; 
     this.id = id; 
     this.currentSpeed = 0; 
     this.failedAttempts = 0; 
     this.goalSpeed = 0; 
     this.maxSpeed = 0; 
     this.successAttempts = 0; 
    } 

    synchronized public void setGoalSpeed(int s){ 
     this.goalSpeed = s; 
    } 

    public int getCurrentSpeed(){ 
     return currentSpeed; 
    } 

    synchronized private void setNewSpeed(){ 
     int currentDrain = 0; 
     for(Rotor r : controller.getRotors()){ 
      currentDrain = currentDrain + r.getCurrentSpeed(); 
     } 
     if((currentDrain + (goalSpeed - currentSpeed)) > 20){ 
      //we cannot increase by total amount because drain too high 
      System.out.println("failed"); 
      this.failedAttempts++; 
      currentSpeed = currentSpeed + (20 - currentDrain); 
      System.out.println("currentSpeed:" + currentSpeed); 
     } else { 
      System.out.println("success"); 
      successAttempts++; 
      currentSpeed = goalSpeed; 
     } 
//  System.out.println("goalSpeed:" + goalSpeed); 
//  System.out.println("currentDrain:" + currentDrain); 

} 

    public void run() { 
     try { 
      while(true){ 
       setNewSpeed(); 
       if(currentSpeed > maxSpeed){ 
        maxSpeed = currentSpeed; 
       } 

       Thread.sleep(Y); 
      } 
     } catch (InterruptedException e) { 
      System.out.println("Rotor " + id + ": checks=" + (int)(successAttempts + failedAttempts) + ", success rate=" + successAttempts + ", failedAttempts=" + failedAttempts + ", max=" + maxSpeed); 
     } 
    } 
} 

ответ

1

Синхронизировать с замком, общим для всех роторов. Теперь каждый из них синхронизирует свою блокировку (то есть this), поэтому, хотя метод синхронизирован, он может одновременно вызываться на разных объектах.

0

Самый простой способ их синхронизации - использовать метод static synchronized.

Таким образом, использование явного объекта блокировки, совместно используемого между экземплярами, вероятно, является лучшим подходом.

+0

Он не может получить доступ к свойствам экземпляра из статического метода. – Kayaman

+0

@ Kayaman Однако он может передать экземпляр в параметр, а затем обратиться к приватным методам или даже к частным членам переданного экземпляра. –

+0

Конечно, если он переключит дизайн вокруг. – Kayaman

0

1) Вы не должны писать

synchronized private void setNewSpeed() и synchronized public void setGoalSpeed(int s)

но private synchronized void setNewSpeed() и public synchronized void setGoalSpeed(int s), если вы хотите соблюдать соглашения и стандарты.

2) Вы объявляете два синхронизированных метода в своем классе Rotor Runnable, но это бессмысленно, потому что в синхронизированных методах вы не управляете данными, разделяемыми между потоками.

3) У вас есть несколько способов решения вашей проблемы.
Гибкое решение состоит из использования искусственного объекта, совместно используемого между потоками, и выполнения блокировки этого объекта при вызове метода setNewSpeed().
Позволяет каждому протектору дождаться блокировки перед входом в setNewSpeed().

Вот идея реализовать решение:

  • Перед инстанцирования Rotor, создать общий объект таким образом:

    Object lockObject = new Object();

  • изменение public Rotor(Controller c, int Y, int id) к public Rotor(Controller c, int Y, int id, Object lockObject)

  • вызовите конструктор Rotor, добавив тот же экземпляр lockObject для всех Rotors, который вы хотите синхронизировать между собой изменение скорости.

  • Храните lockObject в качестве поля экземпляра ротора в корпусе конструктора.

  • В Rotor использовать lockObject сделать синхронизацию следующим образом:

образца коды:

private void setNewSpeed(){ 
    synchronized(lockObject){ 
     ... your actual processing 
     } 
}