2013-05-08 81 views
5

当前在GUI中生成一个关键事件,然后通过几个类传递给一个在单独线程中运行的类。线程正在等待关键事件,并且在接收到一个关键事件时,更改类链中的变量将被更改(请参见图表)。但是在调试过程中变量不会改变。来自线程的另一个类的访问变量

线程正在访问的类当然是在它自己的线程中,因为它是从GUI调用的,这导致我认为这是一个并发问题。

有没有办法解决这个可能使用原子整数或锁?我已经看到了一些使用同步函数的例子,但是我不能让它们工作,因为它们没有解释类的需求。 (我的意思是他们给你的代码做同步,但他们没有解释如何使一个类“同步”)。

Diagram of class structure 下面是在E类线程的代码,可以将线程的对象引用从上方从类接收上述等一类的基准的类设置

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类中的线程并逐步完成,代码将正常运行并处理器。我收到四个值。但是,当我不调试那个线程时,处理器中没有任何事情发生,这就是为什么我认为这可能是一个并发问题。

使我在Class B和Atomic Integer中访问的变量,也使一些使用的功能同步。调试环境:(之外仍然dosent功能

代码在B级从E类称为

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

该KeyEvent在GUI类通过的KeyListener产生(whenver一个键被按下时触发),该KeyEvent对象然后通过几个“滴入”函数传递给E类,这些函数只传递给下一个类,因此GUI调用processor.setKeyevent(e),处理器然后调用bus.setKeyevent(e)等等直到KeyEvent属性设置在E类中。

系统初始化后,E类中的线程启动,is不断检查Keyevent属性的值,一旦KeyEvent不为null,即它已从GUI(通过其他所有内容)传递过来,E类然后在类B中设置整数属性的值。

发生了什么当键被按下时什么也没有发生,应该发生的事情是该整数是类B应该改变,因为类E,但它不是。由于net beans不允许我一次调试两个线程,所以它让我有点尴尬,当我在E类中的线程之外的代码中放置断点时,它不起作用,就好像线程没有运行或者作为如果它没有收到keyevent,如果我在线程中放置断点而不在外面工作,那么B类中I的值会改变。如果它在调试之外运行,它将无法工作:/

+0

显示源。 E类的实例如何获得对B类的引用? – digitaljoel 2013-05-08 20:49:28

+0

你说过“在调试过程中变量没有改变”。你可以发布打印调试的代码和修改变量的代码(在其他类中)吗? – KyleM 2013-05-08 20:50:07

+0

发送'ClassB'的对象作为参数,直到达到'ClassE',也许? – Goodwine 2013-05-08 20:55:02

回答

3

E类不应该直接操作B类中的数据成员。这是各种不好的。但这不是你问题的关键。

为了让B中的GUI线程看到E中线程所做的更改,您需要使用某种同步控制。通常我会建议使用AtomicInteger,但是你提到了一些swing的东西,所以我假设B类实际上是一个Swing组件。在那种情况下,我发现把东西摆在EDT上是更清洁的,并且让E有责任在EDT上打电话给B。

这是我的意思。无论如何,我已经消除了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 2013-05-09 08:13:00

+0

我在系统中添加了原子整数,运行时仍然没有正常运行如果我在E类的线程中放置了一个断点,然后运行调试,那么一切都可以正常工作,不知道我还能做什么,因为不太熟悉Java中的并发性:/ – Samishalt 2013-05-09 18:49:32

+0

你可以在你的问题中增加一些代码吗?具体来说就是从E中调用的B中的代码,以及传入键事件的E中的代码,以及随后调用B的代码 你能澄清一下什么是不工作吗?E中的代码永远不会得到关键事件,B永远不会被调用,B是被调用的,但值不会改变吗? – wolfcastle 2013-05-09 19:01:07