我有一个GUI(在其EDT线程上)和另一个名为“Recorder”的线程,如果按下按钮,则由GUI的eventListener创建:
if(actionEvent.getSource().equals(ui.record)) {
if(recorderThread == null) {
recorder = new Recorder();
recorderThread = new Thread(recorder);
recorderThread.start();
}
}
在同一个事件监听器中,我还实现了一个mouseListener。
public void mouseReleased(MouseEvent mEvent) {
int x, y;
x = mEvent.getXOnScreen();
y = mEvent.getYOnScreen();
}
单击鼠标时,我想将这些X和Y变量传递给记录器线程中的记录器对象。我想我可以提出一个带有volatile变量的解决方案,但我在某处读到了处理程序可用于在两个线程之间传递信息或调用方法,并且有兴趣了解它。我发现this previous post面临与我类似的问题。
然而,该帖子的解决方案让我很困惑。我认为这个人将线程对象传递给处理程序,这样任何线程都可以调用该处理程序中的所有对象?例如:
handler(someObj);
然后在另一个线程
handler.getSomeObj().methodInObj();
但我不完全确定这是否是处理程序的工作原理。此外,他们似乎也在处理Swing的后台线程而不是用户创建的单独线程(如果这是相同的概念,请提前道歉)。
最后,该解决方案似乎已经在Java库中调用了一个Handler类,而我想编写自己的处理程序类,这样我就可以更好地了解线程的通信方式(因为我是一个非常熟悉youtube的程序员)。如果有人可以帮助我,我们将不胜感激。提前谢谢!
答案 0 :(得分:2)
另一方面,线程的概念与类的概念(包括其成员的实例)之间存在差异。
线程可以通过多种方式进行通信(意味着在一个可以由其他线程写入或读取的位置读取或写入变量。在您的示例中,我将让您的Recorder类公开一个公共方法addCoordinates()。记录器有一个私有列表成员,其中存储了添加的坐标。真正的问题是对此列表的同步访问:您必须确保没有一个线程读取列表而另一个线程同时添加新记录。最简单的解决方案是有一个同步列表:
private List<Coordinates> myCoordinates = Collections.synchronizedList( new ArrayList<>());
public void addCoordinates( Coordinates coordinates)
{
// this runs in the context of your GUI thread
myCoordinates.add(coordinates);
synchronized(this)
{
this.notify(); // wakes up the recorder thread
}
}
public void run()
{
// this runs in the context of the Recorder thread
while ( true)
{
synchronized(this)
{
this.wait(); // waits until the 'this' is notified
}
for( Coordinates c : myCoordinates)
{
// do something
}
}
}
答案 1 :(得分:2)
录音机只是创建一个名为“Point”的对象列表,用于存储鼠标点击的X和Y位置,稍后由自动转换器使用
然后记录器不应该在自己的线程中运行,因为不需要这样做,而只需直接从EDT线程上的
例如:
import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.GridLayout;
import java.awt.Point;
import java.awt.event.ActionEvent;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.util.ArrayList;
import java.util.List;
import javax.swing.*;
@SuppressWarnings("serial")
public class TestRecorder extends JPanel {
private static final int GAP = 3;
private MyRecorder myRecorder = new MyRecorder();
private boolean recording = false;
public TestRecorder() {
JPanel btnPanel = new JPanel(new GridLayout(1, 0, GAP, 0));
btnPanel.add(new JButton(new StartAction("Start")));
btnPanel.add(new JButton(new StopAction("Stop")));
btnPanel.add(new JButton(new ShowAction("Show")));
addMouseListener(new MyMouse());
setBorder(BorderFactory.createEmptyBorder(GAP, GAP, GAP, GAP));
setPreferredSize(new Dimension(500, 400));
setLayout(new BorderLayout());
add(btnPanel, BorderLayout.PAGE_END);
}
private class MyMouse extends MouseAdapter {
@Override
public void mousePressed(MouseEvent e) {
if (recording) {
myRecorder.addPoint(e.getPoint());
}
}
}
private class StartAction extends AbstractAction {
public StartAction(String name) {
super(name);
}
@Override
public void actionPerformed(ActionEvent e) {
recording = true;
}
}
private class StopAction extends AbstractAction {
public StopAction(String name) {
super(name);
}
@Override
public void actionPerformed(ActionEvent e) {
recording = false;
}
}
private class ShowAction extends AbstractAction {
public ShowAction(String name) {
super(name);
}
@Override
public void actionPerformed(ActionEvent e) {
System.out.println("Points:");
for (Point point : myRecorder.getPoints()) {
System.out.println(point);
}
System.out.println();
}
}
public static void main(String[] args) {
SwingUtilities.invokeLater(() -> createAndShowGui());
}
private static void createAndShowGui() {
TestRecorder mainPanel = new TestRecorder();
JFrame frame = new JFrame("TestRecorder");
frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
frame.add(mainPanel);
frame.pack();
frame.setLocationByPlatform(true);
frame.setVisible(true);
}
}
public class MyRecorder {
private List<Point> points = new ArrayList<>();
public List<Point> getPoints() {
return points;
}
public void addPoint(Point p) {
points.add(p);
}
}