Java 从线程访问另一个类中的变量

Java 从线程访问另一个类中的变量,java,concurrency,Java,Concurrency,此时,GUI中会生成一个键事件,然后该事件会通过几个类传递给在单独线程中运行的类。线程正在等待一个键事件,当收到一个来自更高级别的变量时,类链被改变(参见图)。但是,在调试期间,变量不会更改 线程访问的类当然在它自己的线程中,因为它是从GUI调用的,这让我认为这是并发性的问题 有没有一种方法可以解决这个问题,也许是使用原子整数或锁?我已经看到了一些使用同步函数的示例,但是我无法让它们工作,因为它们没有解释类的需求。(我的意思是,他们给了您执行同步的代码,但没有解释如何使类“可同步”) 这里是来

此时,GUI中会生成一个键事件,然后该事件会通过几个类传递给在单独线程中运行的类。线程正在等待一个键事件,当收到一个来自更高级别的变量时,类链被改变(参见图)。但是,在调试期间,变量不会更改

线程访问的类当然在它自己的线程中,因为它是从GUI调用的,这让我认为这是并发性的问题

有没有一种方法可以解决这个问题,也许是使用原子整数或锁?我已经看到了一些使用同步函数的示例,但是我无法让它们工作,因为它们没有解释类的需求。(我的意思是,他们给了您执行同步的代码,但没有解释如何使类“可同步”)

这里是来自类E中线程的代码,正如您可以看到的那样,线程的对象引用是从上面的类设置的,该类从上面的类接收类a的引用,等等

    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中的线程并逐步执行它,那么代码可以正常运行,处理器也可以运行。我收到的值为4。然而,当我不调试该线程时,处理器中什么也没有发生,这就是为什么我认为这可能是一个并发问题

使我在类B和原子整数中访问的变量,也使一些使用的函数同步。调试环境之外的Still dosent函数:(

从类E调用的类B中的代码

    public void SetI(int value){//also tried using synchronized as well
        I.set(value);
    }
KeyEvent由一个keyListener在GUI类中生成(当按下一个键时触发)。KeyEvent对象然后通过几个“涓流”函数传递给类E,这些函数只需将其传递给下一个类,因此GUI调用processor.setKeyevent(E),处理器然后调用bus.setKeyevent(E)以此类推,直到KeyEvent属性设置在类E中

在系统初始化时,类E中的线程启动,并不断检查Keyevent属性的值,一旦Keyevent不为null,即它已从GUI(通过其他一切)传递给类E,然后设置类B中整数属性的值


当按下一个键时,什么也没有发生,应该发生的是,整数是B类,因为E类,所以B类应该改变,但它不是。由于NetBeans不允许我一次调试两个线程,这使它有点尴尬,当我在E类线程外的代码中放置断点时,它没有工作,就好像线程没有运行或者没有接收到keyevent一样,如果我在线程中放置断点而没有在线程外工作,那么B类中i的值就会改变。如果它在调试之外运行,它就不会工作://

如果没有一些代码,很难判断,但是您可能想看看java.util.concurrent。这是一种安全的方法线程之间的nd消息使用阻塞队列


该链接中的Java API页面提供了一个很好的代码示例。

类E不应该直接操作类B中的数据成员。这是各种各样的错误。但这并不是问题的关键所在

为了让B中的GUI线程看到E中的线程所做的更改,您需要使用某种类型的同步控制。通常我建议使用
AtomicInteger
,但是您提到了一些swing组件,所以我假设B类实际上是一个swing组件。在这种情况下,我发现打开swing组件更干净EDT,让E负责给B打电话

这就是我的意思。我删除了C类和D类,因为它们只是传递。我还忽略了线程的构造/设置和启动。我删除了E中的忙循环,并用一个
倒计时闩锁
替换了它

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

看一看

显示源代码。类E的实例是如何获得对类B的引用的?您说过“在调试期间,变量不会更改”。您能将代码发布到打印调试的地方吗?代码(在另一个类中)这会修改变量?将
ClassB
的对象作为参数发送,直到它到达
ClassE
,也许?在B中创建C、D、E?子类可以访问其封闭类的所有变量和方法。您使类“可同步”有两种方法,第一种方法是将synchronized添加到所有方法或尽可能多的方法:“public synchronized void yourMethod(){}”或向所有方法添加相同的锁,如下所示:“private Object yourLock=new Object();public void yourMethod(){synchronized(yourLock){]}”感谢您的帮助。我完全知道,这种结构几乎违反了所有面向对象的范式法则,但是,尽管这样做让我非常痛苦,但必须按照客户的要求以这种方式进行:(.再次感谢。我已将原子整数添加到系统中。运行时仍然无法正常运行。如果我在类E中的线程中放置断点并运行调试,则一切正常。不确定我还可以做什么,因为我对Java中的并发性不太熟悉:/能否为您的问题添加更多代码?特别是B中的代码at是从E调用的,E中传递关键事件的代码,以及随后调用B的代码。您还可以澄清什么不起作用吗?E中的代码是否从未获得关键事件,B是否从未被调用,B是否被调用,但值没有改变?已在原始帖子中添加。抱歉,延迟回复,我想我理解如何工作,在您的评论中提到,闩锁si用于一次性使用,是否有可能使其不是一次性使用,因为每次按键时都需要运行代码,我是否可以通过将其设置为线程中某个新的闩锁对象来实现这一点?