2013-10-06 66 views
0

一位朋友最近要求我製作一個簡單的蜂鳴器程序,並在我爲他寫的內容中發現了一個奇怪的「錯誤」。在JVM7中凍結,但在JVM6中凍結

如果按下鍵並且蜂鳴器在幾秒鐘內迅速復位,他會觀察到復位後第一次按鍵和「蜂鳴」指示之間出現的程序的2到3秒鐘凍結。他具有以下Java安裝:

build 1.7.0_25-b16 

不過,我並不在我的電腦上遇到此問題,用下面的Java安裝:

$ java -version 
java version "1.6.0_51" 
Java(TM) SE Runtime Environment (build 1.6.0_51-b11-457-10M4509) 
Java HotSpot(TM) 64-Bit Server VM (build 20.51-b01-457, mixed mode) 

一旦解凍,程序返回相應的鍵(即不是按下的最後一個鍵,而是在重置之後和凍結之前推動的第一個鍵)。這表明問題不在聆聽者身上,而在於對聆聽者的反應。

有什麼想法可能會導致這種現象?在此先感謝您的幫助。

的源代碼:

/** 
* Buzzer.java 
* 
* Buzzer 
*/ 
package org.lexingtonma.lhs.nhb; 

import java.awt.Color; 
import java.awt.DefaultKeyboardFocusManager; 
import java.awt.Font; 
import java.awt.KeyEventDispatcher; 
import java.awt.event.ActionEvent; 
import java.awt.event.ActionListener; 
import java.awt.event.KeyEvent; 
import java.awt.event.KeyListener; 

import javax.sound.sampled.AudioSystem; 
import javax.sound.sampled.Clip; 
import javax.sound.sampled.LineUnavailableException; 
import javax.swing.JButton; 
import javax.swing.JFrame; 
import javax.swing.JOptionPane; 
import javax.swing.JPanel; 
import javax.swing.JTextField; 


/** 
* @author Arman D. Bilge 
* 
*/ 
public class Buzzer extends JFrame implements KeyListener { 

    private static final long serialVersionUID = 7492374642744742658L; 
    private static final String BUZZ_A = "BuzzA.wav"; 
    private static final String BUZZ_B = "BuzzB.wav"; 
    private Clip buzz = null; 
    private boolean listening = true; 
    private final JTextField display = new JTextField(3); 
    private final JButton reset = new JButton("Reset"); 

    { 

     DefaultKeyboardFocusManager.getCurrentKeyboardFocusManager() 
      .addKeyEventDispatcher(new KeyEventDispatcher() { 
       public boolean dispatchKeyEvent(KeyEvent e) { 
        keyTyped(e); 
        return false; 
       } 
      }); 
     setTitle("Buzzer"); 
     final JPanel panel = new JPanel(); 
     setSize(256, 162); 
     setDefaultCloseOperation(EXIT_ON_CLOSE); 
     display.setFont(new Font("Helvetica", Font.BOLD, 64)); 
     display.setForeground(Color.WHITE); 
     display.setVisible(true); 
     display.setEditable(false); 
     display.setHorizontalAlignment(JTextField.CENTER); 
     panel.add(display); 
     reset.addActionListener(new ActionListener() { 
      @Override 
      public void actionPerformed(ActionEvent e) { 
       display.setText(""); 
       display.setBackground(Color.WHITE); 
       listening = true; 
       reset.setEnabled(false); 
      } 
     }); 
     reset.setEnabled(false); 
     panel.add(reset); 
     add(panel); 
     try { 
      buzz = AudioSystem.getClip(); 
     } catch (LineUnavailableException e) { 
      JOptionPane.showMessageDialog(this, e.getLocalizedMessage(), "FATAL ERROR", JOptionPane.ERROR_MESSAGE); 
     } 
    } 

    public static final void main(String args[]) { 
     Buzzer b = new Buzzer(); 
     b.setVisible(true); 
    } 

    public void keyPressed(KeyEvent e) { 
     // Do nothing   
    } 

    public void keyReleased(KeyEvent e) { 
     // Do nothing   
    } 

    public void keyTyped(KeyEvent e) { 
     final char c = e.getKeyChar(); 
     if (listening && Character.isLetterOrDigit(c)) { 
      buzz.close(); 
      listening = false; 
      if (Character.isDigit(c)) { 
       display.setBackground(Color.RED); 
       try { 
        buzz.open(AudioSystem.getAudioInputStream(getClass().getResource(BUZZ_A))); 
        buzz.start(); 
       } catch (Exception ex) { 
        JOptionPane.showMessageDialog(this, ex.getLocalizedMessage(), "FATAL ERROR", JOptionPane.ERROR_MESSAGE); 
        System.exit(1); 
       } 
      } else { 
       display.setBackground(Color.BLUE); 
       try { 
        buzz.open(AudioSystem.getAudioInputStream(getClass().getResource(BUZZ_B))); 
        buzz.start(); 
       } catch (Exception ex) { 
        JOptionPane.showMessageDialog(this, ex.getLocalizedMessage(), "FATAL ERROR", JOptionPane.ERROR_MESSAGE); 
        System.exit(1); 
       } 
      } 
      display.setText("" + c); 
      reset.setEnabled(true); 
     } 

    } 

} 

罐:https://www.dropbox.com/s/62fl2i97m9hrx9m/Buzzer.jar

+0

什麼操作系統? – sage88

+0

他在Windows 7上;我在Mac OS X 10.6上。這個問題也出現在Mac OS X上的JVM7安裝中。 – Arman

+0

因此,在OSX和Win 7中都存在1.7的bug? (我有一些鍵綁定和1.7和OSX的問題,但在Win 7中一切正常,所以我想我會問) – sage88

回答

2

每次創建一個新的Clip對象並丟棄舊對象會更安全。試試這個方法

public static void play(String name) { 
    try{ 
    AudioInputStream sounds = AudioSystem.getAudioInputStream(Buzzer.class.getResource(name)); 
    final Clip clip = AudioSystem.getClip(); 
    clip.addLineListener(new LineListener() { 
     public void update(LineEvent e) { 
      LineEvent.Type type = e.getType(); 
      if(type == type.STOP) clip.close(); 
     } 
    }); 
    clip.open(sounds); 
    clip.start(); 
    } catch(Exception e){ 
     e.printStackTrace(); 
    } 

}

+0

btw。你讀過Clip.open的API文檔嗎?它說:「在已打開的行上調用此方法是非法的,可能會導致IllegalStateException」 – SpiderPig

+0

謝謝,這工作!不,我沒有仔細查看API,但是我認爲在每個open()之前使用'close()'會阻止這種情況發生? – Arman

+0

打開和關閉方法都是非阻塞的。即調用close()立即返回而不等待剪輯實際關閉。所以當你打開時,剪輯可能還沒有關閉。 – SpiderPig

1

至於有人建議,你可以給一個鍵綁定嘗試看看是否有幫助。這只是顯示如何使用Enter鍵完成此操作。

public class Buzzer extends JFrame { 
private static final String enter = "ENTER"; 
    public Buzzer() { 
     // Key bound AbstractAction item 
     enterAction = new EnterAction(); 
     // Gets the JFrame InputMap and pairs the key to the action 
     this.getInputMap().put(KeyStroke.getKeyStroke(enter), "doEnterAction"); 
     // This line pairs the AbstractAction enterAction to the action "doEnterAction" 
     this.getActionMap().put("doEnterAction", enterAction); 
    } 

    private class EnterAction extends AbstractAction { 
     @Override 
     public void actionPerformed(ActionEvent e) { 
      System.out.println("Enter was pressed."); 
     } 
    } 
} 

其實我不記得這是否會工作時,應用到一個JFrame,你可能需要做一個JPanel首次把這些申請。只需用面板名稱替換「this」即可。

+0

我是否需要爲每個KeyStroke制定單獨的規則?還是有一個簡單的方法來捕獲所有按鍵,然後對它們執行邏輯?這個答案似乎不建議:http:// stackoverflow。com/a/15422641/1642693 – Arman

+0

如果您想將幾個鍵映射到同一個函數,那麼當您執行getActionMap.put()時,您可以將它們全部綁定到相同的操作,但是無法執行一系列鍵,鍵綁定旨在將單個鍵事件映射到操作。 – sage88