2013-05-08 3 views
5

В настоящее время в графическом интерфейсе создается ключевое событие, которое затем передается через несколько классов и присваивается классу, который выполняется в отдельном потоке. Поток ожидает ключевое событие, и когда один получает переменную от дальнейшего, цепочка классов изменяется (см. Диаграмму). Однако во время отладки переменная не меняется.Доступ к переменной из другого класса из потока

Класс, к которому обращается поток, конечно, находится в своем потоке, поскольку он вызывается из графического интерфейса, что заставило меня думать, что это проблема с параллелизмом.

Есть ли способ решить эту проблему, используя атомные целые числа или блокировки? Я видел несколько примеров, используя синхронизированные функции, но я не могу заставить их работать, поскольку они не объясняют требования классов. (я имею в виду, что они дают вам код для синхронизации, но они не объясняют, как сделать класс «синхронизированным»).

Diagram of class structure Вот код из Нити в классе Е, как вы можете ссылка на объект Нити имеет значение от класса выше, который получает ссылку класса А из класса выше и т.д.

private Processor processor; 

    public void run() { 
     while (true) { 
      if (keyevent != null) { 


       keyevent = null; 
       processor.I = 4; 
      } 
     } 
    } 

    public void SetProcessor(Processor processor) { 
     this.processor = processor; 
    } 

Расширение комментария к отладке. Во время отладки, если я только отлаживаю поток в классе E и прохожу через него, код отлично работает и процессор. Я получаю значение четыре. Однако, когда я не отлаживаю этот поток, в процессоре ничего не происходит, поэтому я думал, что это может быть проблема параллелизма.

Сделано varaible, к которому я обращаюсь в классах B и Atomic Integer, также сделал некоторые из функций, используемых также синхронизированными. Тем не менее функция вне доцент отладочной среды :(

код в классе B называется из класса Е

public void SetI(int value){//also tried using synchronized as well 
     I.set(value); 
    } 

KeyEvent генерируется в классе GUI с помощью KeyListener (который стреляет whenver нажатии клавиши). Объект KeyEvent затем передается классу E с помощью нескольких функций «trickle down», которые просто передают его на следующий класс, поэтому GUI вызывает процессор.setKeyevent (e), тогда процессор вызывает bus.setKeyevent (e) и так далее вперед до тех пор, пока свойство KeyEvent не будет установлено в классе E.

После инициализации системы начинается поток в классе E, постоянно проверяет значение свойства Keyevent, как только KeyEvent не является нулевым, то есть он был передан один из GUI (через все остальное). Класс E затем устанавливает значение целочисленного свойства в классе B.

Что происходит заключается в том, что при нажатии клавиши ничего не происходит, что должно происходить, так это то, что целое число класса B должно меняться из-за класса E, но это не так. Поскольку сетевые бобы не позволяют мне отлаживать сразу два потока, это делает его немного неудобным, когда я помещал контрольные точки в код за пределами потока в классе E, он не работает, как будто поток не работает или как если он не получает keyevent, если я поставил точки останова в потоке, а не за его пределами, значение I в классе B будет изменено. Если он запускается за пределами отладки, его доза не работает:/

+0

Показать источник. Как экземпляр класса E получает ссылку на класс B? – digitaljoel

+0

Вы сказали, что «во время отладки переменная не изменяется». Можете ли вы опубликовать код, на котором распечатывается отладка, и код (в другом классе), который изменяет переменную? – KyleM

+0

Отправлять объект «ClassB» в качестве параметра, пока он не достигнет «ClassE», может быть? – Goodwine

ответ

3

Класс E не должен непосредственно манипулировать данными в классе B. Это все виды плохого. Но на самом деле это не проблема вашей проблемы.

Чтобы поток GUI в B отображал изменения, внесенные нитью в E, вам необходимо использовать какой-то контроль синхронизации. Обычно я предлагаю использовать AtomicInteger, однако вы упомянули некоторые вещи качания, поэтому я предполагаю, что класс B на самом деле является компонентом Swing. В этом случае я считаю, что чище держать качели на EDT и нести ответственность E за вызов B на EDT.

Вот что я имею в виду. Я исключил классы C и D, так как они все равно проходят через проход. Я также игнорирую конструкцию/настройку и запуск потока. Я удалил вашу занятую петлю в E и заменил ее на CountDownLatch.

/** 
* Some GUI class, should only be accessed from the EDT 
*/ 
public class B extends JPanel { 

    private int value = 0; 

    private E thatThreadObject; 

    public void setE(E e) { 
     thatThreadObject = e; 
    }  
    public void setValue(int newValue) { 
     value = newValue; 
     System.out.println("Got a new int value: " + value); 
    } 

    public void triggerKeyEvent() { 
     thatThreadObject.keyEvent(); 
    } 
} 

/** 
* Must be thread-safe, as accessed from multiple threads 
*/ 
public class E implements Runnable{ 
    private B thatGuiObject; 
    // Note, latch is only good for one-time use. 
    private final CountDownLatch latch = new CountDownLatch(1); 

    public void setB(B b) { 
     thatGuiObject = b; 
    } 

    public void keyEvent() { 
     // Wake up the waiting thread 
     latch.countDown();    
    } 

    @Override 
    public void run() { 
     try { 
      // Wait for key event forever, better than busy looping 
      latch.await(); 
      // Update B, but it's a Swing component so use EDT 
      EventQueue.invokeLater(new Runnable() { 
       @Override 
       public void run() { 
        thatGuiObject.setValue(4); 
       } 
      }); 
     } 
     catch (InterruptedException e) { 
      e.printStackTrace(); 
     }    
    } 
} 

Взгляните на Java Concurrency Tutorial

+0

Спасибо за помощь. Я полностью осознаю, что такая структура нарушает почти каждый закон, ориентированный на объектно-ориентированный парадигм, но насколько мне больно это делать, это должно быть сделано, поскольку клиент попросил его так :(Еще раз спасибо – Samishalt

+0

Я добавил атомное целое в систему. Все еще не работает должным образом при запуске. Если я положу точку останова в потоке в классе E и запустил debug, тогда все будет работать. Не уверен, что еще я могу сделать, не слишком знакомый с параллелизм в Java:/ – Samishalt

+0

Можете ли вы добавить еще один код в свой вопрос? В частности, код в B, который вызывается из E, и код в E, где передается событие ключа, а также код, который затем вызывает B Можете ли вы также уточнить, что не работает? Является ли код в E, никогда не получающим ключевое событие, является ли B не вызываемым, вызывается ли B, но значение не изменяется? – wolfcastle

0

Трудно сказать без какого-либо кода, но вы можете взглянуть на java.util.concurrent. Безопасный способ отправки сообщений между потоками - использовать BlockingQueues.

http://docs.oracle.com/javase/7/docs/api/java/util/concurrent/BlockingQueue.html

страница API Java в этой связи представляет собой хороший пример кода.

Смежные вопросы