Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/multithreading/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
在Java中使用Synchronized关键字_Java_Multithreading_Synchronized - Fatal编程技术网

在Java中使用Synchronized关键字

在Java中使用Synchronized关键字,java,multithreading,synchronized,Java,Multithreading,Synchronized,我读过一些关于同步方法的文章(包括Oracle的),我不确定我是否理解正确 我有以下代码: public class Player extends javax.swing.JLabel implements Runnable{ private static int off2[] = {-1, 0, 1, 0}, off1[] = {0, 1, 0, -1}; private static final Map dir = new java.util.HashMap<Integ

我读过一些关于同步方法的文章(包括Oracle的),我不确定我是否理解正确

我有以下代码:

public class Player extends javax.swing.JLabel implements Runnable{
    private static int off2[] = {-1, 0, 1, 0}, off1[] = {0, 1, 0, -1};
    private static final Map dir = new java.util.HashMap<Integer, Integer>();
    static{
        dir.put(KeyEvent.VK_UP, 0);
        dir.put(KeyEvent.VK_RIGHT, 1);
        dir.put(KeyEvent.VK_DOWN, 2);
        dir.put(KeyEvent.VK_LEFT, 3);
    }
    private boolean moving[] = new boolean[4];

    @Override
    public void run(){
        while(true){
            for(Object i : dir.values()){
                if(isPressed((Integer)i)) setLocation(getX() + off1[(Integer)i], getY() + off2[(Integer)i]);
            }
            try{
                Thread.sleep(10);
            }catch(java.lang.InterruptedException e){
                System.err.println("Interrupted Exception: " + e.getMessage());
            }
        }
    }
    public void start(){
        (new Thread(this)).start();
    }

    private synchronized boolean isPressed(Integer i){
        if(moving[i]) return true;
        else return false;
    }

    public synchronized void setPressed(KeyEvent evt) {
        if(dir.containsKey(evt.getKeyCode()))moving[(Integer)dir.get(evt.getKeyCode())] = true;
    }
    public synchronized void setReleased(KeyEvent evt){
        if(dir.containsKey(evt.getKeyCode()))moving[(Integer)dir.get(evt.getKeyCode())] = false;
    }
}
公共类播放器扩展javax.swing.JLabel实现可运行{
私有静态int off2[]={-1,0,1,0},off1[]={0,1,0,1};
private static final Map dir=new java.util.HashMap();
静止的{
目录put(KeyEvent.VK_UP,0);
方向放置(KeyEvent.VK_RIGHT,1);
方向放置(KeyEvent.VK_DOWN,2);
方向放置(KeyEvent.VK_左,3);
}
私有布尔移动[]=新布尔[4];
@凌驾
公开募捐{
while(true){
对于(对象i:dir.values()){
if(isPressed((Integer)i))设置位置(getX()+off1[(Integer)i],getY()+off2[(Integer)i]);
}
试一试{
睡眠(10);
}catch(java.lang.InterruptedException e){
System.err.println(“中断异常:+e.getMessage());
}
}
}
公开作废开始(){
(新线程(此)).start();
}
私有同步布尔值isPressed(整数i){
如果(移动[i])返回true;
否则返回false;
}
按下公共同步无效设置(KeyEvent evt){
如果(dir.containsKey(evt.getKeyCode())移动[(Integer)dir.get(evt.getKeyCode())]=true;
}
已发布公共同步无效设置(KeyEvent evt){
如果(dir.containsKey(evt.getKeyCode())移动[(Integer)dir.get(evt.getKeyCode())]=false;
}
}

现在它所做的只是运动。我的理解是,当我的主窗体的键侦听器注册按键按下和释放事件时,setPressed和setrelease从主线程调用。这个准则合理吗?是否正确使用synchronized关键字?(代码在没有它的情况下可以工作,但我怀疑最好有它?

使用synchronized是正确的,但我认为没有必要,因为在当前的实现中,对阵列的并行访问不会导致不一致

但是,我认为您的代码中存在一个不同的线程问题。您不应该从单独的线程与Swing(=调用setLocation())交互,请参阅。因此,您需要将更新代码包装成可运行的:

private boolean moving[] = new boolean[4];
Runnable dirUpdate = new Runnable() {
  for(Object i : dir.values()){
    if(isPressed((Integer)i)) setLocation(getX() + off1[(Integer)i], getY() + off2[(Integer)i]);
  }
};
来自线程的调用将如下所示:

SwingUtils.invokeLater(dirUpdate);
请注意,在这种情况下,不再需要同步,因为将从事件处理线程调用dirUpdate

您可能希望在isPressed()中检查null,以避免未映射键出现异常


对于移动来说,一个更简单的表示方式可能是使用dx和dy变量,这些变量将由键事件设置为-1、1或0。

不确定事情的摇摆面,但一般来说,您需要同步来保护可能由多个线程访问的共享数据(在您的情况下是移动[])

在这种情况下,您需要同步,因为在setXxx方法(主线程)写入时或在您启动的线程读取时可能会访问moving[]

自java 5以来,Java.Actudio包中的设备要好得多,我建议您考虑使用锁来保护Actudi[]或ActuiBooLo../P>。 几个“风格问题”:

  • 不要使用“原始类型”-更喜欢映射而不是映射(这也可以避免setXxxx()方法中未经检查的丑陋强制转换)

  • 避免使用一行if--使代码难以辨认:)

  • 如果您决定使用Lock(在本例中,这不是一个很大的优势v.synchronized),您的isPressed()应该如下所示:

    // ...
    private Lock movingLock = new ReentrantLock();
    
    private  boolean isPressed(Integer i){
      try {
        movingLock.acquire();
        return moving[i];
      } finally
        movingLock.release();
      }        
    }
    

    您必须通过调用Lock.acquire()和release()“包装”setXxx方法中对moving[]的赋值。

    怀疑这样做是不好的理由,在这种情况下也是不正确的。您能告诉我为什么不正确吗?您能告诉我哪两个线程将同时调用这些方法中的任何一个吗?
    if(moving[i])返回true;否则返回false
    应该是
    return-moving[i]
    足够正确,该方法是匆忙编写的。我有一个处理键盘输入的主框架,然后调用“Player”类方法。因此“Player”中的移动线程和主线程可以同时访问移动[]数组。如果需要的话,我可以在代码中进行编辑,但我认为这是不必要的。你能帮助我理解为什么我不能从两个线程与类交互吗?我查看了该链接,但它并没有真正帮助我……Swing不是线程安全的——基本上它不使用synchronized anywhere来保持设计简单和无死锁。因此,当您从单独的线程与swing交互时,您需要使用invokeLater。好的,谢谢。我想我现在明白了:通过invokeLater()将Runnable放在一个要完成的事情队列中?然后在一个单独的线程中一次执行一个?这是正确的吗?是的。我用一些代码片段更新了答案,以说明它是如何使用的;非常感谢。非常有帮助!除此之外,还有你提到的其他事情,代码看起来还行吧?还有,为什么从事件处理线程调用dirUpdate()可以消除同步的需要?那根线能提供某种安全吗?好的。非常感谢你。这个回答为我澄清了一些事情。首先,很明显我没有疯,因为你似乎明白我说的多线程访问它的意思,哈哈。第二,谢谢你提供的关于原始类型的提示。那个石膏让我很烦恼,但我不知道如何修复它。第三,感谢您提供关于锁的提示,但是您能帮助我理解锁的作用和synchronized关键字的作用之间的区别吗?