如何在 Java 中创建这三个线程
How to create these three threads in Java
我是线程的新手,对它们了解不多,但是我主要在努力创建它们。
我创建了一个 GUI 程序,它使用选择排序、插入排序或归并排序对随机生成的整数数组进行重复排序。每次排序都对列表进行操作,列表的大小是 2 的幂。每次排序完成后,将显示已排序的元素数和所用的毫秒数。
我已经完成了 3 个 class,它们是合并、选择和插入。
我的合并排序工作正常,但是我在选择和插入时仍然遇到问题。我不确定我的 'if' 和 'else' 语句是否不正确,或者线程本身是否错误,但我正在努力解决它们。
这是我的 Main class 中的内容。
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.Arrays;
import java.util.Random;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import javax.swing.*;
import javax.swing.border.EmptyBorder;
public class Sorter extends JFrame
{
private static final long serialVersionUID = 1L;
private static final int WIDTH = 400;
private static final int HEIGHT = 300;
public static final String SELECTION_SORT_TEXT = "Selection Sort";
public static final String INSERTION_SORT_TEXT = "Insertion Sort";
public static final String MERGE_SORT_TEXT = "Merge Sort";
private JComboBox sortingAlgorithms;
private JTextArea display;
private JButton sortButton;
private JPanel panel;
private JLabel loadingIcon;
private JLabel sort;
private String[] options = {SELECTION_SORT_TEXT, INSERTION_SORT_TEXT, MERGE_SORT_TEXT};
public Sorter()
{
setTitle("Sorter");
setSize(WIDTH, HEIGHT);
setLayout(new BorderLayout());
setDefaultCloseOperation(EXIT_ON_CLOSE);
createContents();
setVisible(true);
}
private void createContents()
{
//TODO: Implement
this.panel = new JPanel(new FlowLayout());
this.display = new JTextArea();
this.loadingIcon = new JLabel(new ImageIcon("loading.gif"));
this.sort = new JLabel("Sorting Algorithm");
this.sortButton = new JButton("Sort");
this.sortingAlgorithms = new JComboBox<>(options);
loadingIcon.setSize(25,25);
display.setBorder(new EmptyBorder(10,10,10,10));
panel.add(sort);
panel.add(sortingAlgorithms);
panel.add(sortButton);
panel.add(loadingIcon);
sortButton.addActionListener(new SortButtonListener());
loadingIcon.setVisible(false);
display.setEnabled(false);
setLayout(new BorderLayout());
add(panel, BorderLayout.NORTH);
add(display, BorderLayout.CENTER);
}
private class SortButtonListener implements ActionListener
{
private int[] arr;
private SortRunnable sr;
public void actionPerformed(ActionEvent e)
{
sr.run();
ExecutorService es = Executors.newSingleThreadExecutor();
//TODO: Finish Implementation
if(e.getSource() == sortButton)
{
sortingAlgorithms.setEnabled(false);
sortButton.setEnabled(false);
loadingIcon.setVisible(true);
display.setText("N\t\tRuntime (ms)");
}
arr = new int [2000];
for(int i = 0; i <= 8; i++)
{
arr = new int [(int) Math.pow(2, i) * 1000];
fillArr();
sr = new SortRunnable((String) sortingAlgorithms.getSelectedItem(), arr, Sorter.this);
es.execute(sr);
}
Thread sortContext = new Thread(new SortRunnable((String)
sortingAlgorithms.getSelectedItem(), arr, Sorter.this));
sortContext.start();
es.shutdown();
}
/*
These values are powers of 2 from 0 to 8, times 1000.
*/
private void fillArr()
{
Random r = new Random();
int n = 0;
for(int i=0; i<arr.length; ++i)
{
arr[i] = r.nextInt();
}
}
}
/*
The displayResult method is responsible for adding the provided sort runtime information to
the display. It should also check to see if the final sort runtime information is present. If so,
it should hide the loading gif and enable the JComboBox and sort button.
*/
public synchronized void displayResult(int n, long runtime)
{
//TODO: Implement
display.append("\n" + n + "\t\t" + runtime);
}
public static void main(String[] args)
{
new Sorter();
}
}
我不太关心上面的内容。我更关心如何在创建这些线程的 SortRunnable class 中创建我的线程。这是此 class 的预期结果。
此 class 包含用于计时和执行所选排序的代码。
• 您可以找到在排序的开始结束时调用 System.currentTimeMillis() 以获得其 运行 时间的区别。
• 在执行搜索之前在 Runnable 中调用 "Thread.yield()" 以确保 GUI 线程具有根据需要更新其显示所需的优先级。
• 排序完成后,应在 GUI 线程中更新显示。这可以通过在 Sorter 引用上调用 "displayResult" 方法来完成。此调用应在 Runnable 对象的 运行 方法中发生,作为参数传递给 SwingUtilities invokeLater 方法,如:
SwingUtilities.invokeLater(new Runnable()
{
@Override
public void run()
{
//call Sorter's displayResult method here
}
});
这是我需要帮助的代码。
import javax.swing.*;
public class SortRunnable implements Runnable
{
private String sortingAlgorithm;
private int[] arr;
private Sorter sorter;
public SortRunnable(String sortingAlgorithm, int[] arr, Sorter sorter)
{
this.sortingAlgorithm = sortingAlgorithm;
this.arr = arr;
this.sorter = sorter;
}
@Override
public void run()
{
Thread.yield();
if(sortingAlgorithm.equals(sorter.MERGE_SORT_TEXT))
{
MergeSort.mergeSort(arr);
}
Thread.yield();
if(sortingAlgorithm.equals(sorter.SELECTION_SORT_TEXT))
{
SelectionSort.sort(arr);
}
Thread.yield();
if(sortingAlgorithm.equals(sorter.INSERTION_SORT_TEXT))
{
InsertionSort.sort(arr);
}
SwingUtilities.invokeLater(new Runnable()
{
@Override
public void run()
{
Thread.yield();
sorter.displayResult(arr.length, System.currentTimeMillis());
//call Sorter's displayResult method here
}
});
}
}
我只需要有关插入和选择线程的帮助。谢谢!如果您想要他们的个人 classes 以便您可以看到他们里面有什么,请告诉我。
Thread sortContext = new Thread(new SortRunnable(*whatever args you need*));
sortContext.start();
应该可以解决问题,除非您尝试从新线程更新 ui。
SwingUtilities.invokeLater
将请求放入 Swing 的事件队列中进行处理 "at some point in the future"。 Runnable
在事件调度线程的上下文中出列并执行,这意味着您的排序是 运行 在与 UI 相同的线程中,并且将阻塞它直到它完成。
现在,事情变得非常复杂。 Swing 不是线程安全的(这意味着您不应该从事件调度线程上下文外部更新 UI)并且是单线程的,这意味着任何长 运行 或阻塞操作都会阻止 UI 已更新。
"long" 答案是,使用专为这项工作设计的 SwingWorker
。不过,你可以继续使用你的代码,只是有点乱。
您需要捕获更多详细信息,例如排序开始时间和排序结束时间。然后你需要计算这两个时间点之间的毫秒差。
您 "might" 有很多方法可以做到这一点,但是由于 Java 现在有一个不错的新 date/time API,您不妨开始使用它。
然后将此信息传回 UI,可能类似于...
public class SortRunnable implements Runnable
{
private String sortingAlgorithm;
private int[] arr;
private Sorter sorter;
public SortRunnable(String sortingAlgorithm, int[] arr, Sorter sorter)
{
this.sortingAlgorithm = sortingAlgorithm;
this.arr = arr;
this.sorter = sorter;
}
@Override
public void run()
{
LocalDateTime startTime = LocalDateTime.now();
MergeSort.mergeSort(arr);
LocalDateTime endTime = LocalDateTime.now();
long diff = ChronoUnit.MILLIS.between(startTime, endTime)
SwingUtilities.invokeLater(new Runnable()
{
@Override
public void run()
{
sorter.displayResult(arr.length, diff);
}
});
}
}
好的,下一个问题是您没有使用 ExecutorService
。
首先,它确实应该是一个实例字段,因为您不需要继续创建它的更多实例。
其次,你的逻辑无处不在,基本上你想...
- 创建
Sorter
的实例
- 填充数组
- 创建
SortRunnable
的实例
- 将
SortRunnable
提交给ExecutorService
以便它可以被执行...
也许更像...
private ExecutorService es = Executors.newSingleThreadExecutor();
public void actionPerformed(ActionEvent e)
{
fillArr();
Sorter sorter = null;
String algorthim = null;
if(e.getSource() == options[0])
{
// create the instance of Sorter to be used...
sorter = ...
algorthim = ...
}
if(e.getSource() == options[1])
{
// create the instance of Sorter to be used...
sorter = ...
algorthim = ...
}
if(e.getSource() == options[2])
{
// create the instance of Sorter to be used...
sorter = ...
algorthim = ...
}
if (sorter != null) {
SortRunnable sr = new SortRunnable(algorthim, arr, sorter)
es.submit(sr);
}
我创建这些线程的解决方案如下:
在 sortRunnable class 中:
public void run()
{
long store = System.currentTimeMillis();
if(sortingAlgorithm.equals(sorter.MERGE_SORT_TEXT))
{
MergeSort.mergeSort(arr);
}
if(sortingAlgorithm.equals(sorter.SELECTION_SORT_TEXT))
{
SelectionSort.sort(arr);
}
if(sortingAlgorithm.equals(sorter.INSERTION_SORT_TEXT))
{
InsertionSort.sort(arr);
}
SwingUtilities.invokeLater(new Runnable()
{
@Override
public void run()
{
sorter.displayResult(arr.length, System.currentTimeMillis()-store);
//call Sorter's displayResult method here
}
});
}
那是我创建主题的地方。
在我的另一个 class 上,我将它们放入如下:
private class SortButtonListener implements ActionListener
{
private int[] arr;
private SortRunnable sr;
public void actionPerformed(ActionEvent e)
{
ExecutorService es = Executors.newSingleThreadExecutor();
//TODO: Finish Implementation
if(e.getSource() == sortButton)
{
sortingAlgorithms.setEnabled(false);
sortButton.setEnabled(false);
loadingIcon.setVisible(true);
display.setText("N\t\tRuntime (ms)");
}
arr = new int [2000];
for(int i = 0; i <= 8; i++)
{
arr = new int [(int) Math.pow(2, i) * 1000];
fillArr();
sr = new SortRunnable((String) sortingAlgorithms.getSelectedItem(), arr, Sorter.this);
es.execute(sr);
}
es.shutdown();
}
private void fillArr()
{
Random r = new Random();
for(int i=0; i<arr.length; ++i)
{
arr[i] = r.nextInt();
}
}
}
要求其他方法执行的操作,但那是我放入主题的地方。
我是线程的新手,对它们了解不多,但是我主要在努力创建它们。
我创建了一个 GUI 程序,它使用选择排序、插入排序或归并排序对随机生成的整数数组进行重复排序。每次排序都对列表进行操作,列表的大小是 2 的幂。每次排序完成后,将显示已排序的元素数和所用的毫秒数。
我已经完成了 3 个 class,它们是合并、选择和插入。
我的合并排序工作正常,但是我在选择和插入时仍然遇到问题。我不确定我的 'if' 和 'else' 语句是否不正确,或者线程本身是否错误,但我正在努力解决它们。
这是我的 Main class 中的内容。
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.Arrays;
import java.util.Random;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import javax.swing.*;
import javax.swing.border.EmptyBorder;
public class Sorter extends JFrame
{
private static final long serialVersionUID = 1L;
private static final int WIDTH = 400;
private static final int HEIGHT = 300;
public static final String SELECTION_SORT_TEXT = "Selection Sort";
public static final String INSERTION_SORT_TEXT = "Insertion Sort";
public static final String MERGE_SORT_TEXT = "Merge Sort";
private JComboBox sortingAlgorithms;
private JTextArea display;
private JButton sortButton;
private JPanel panel;
private JLabel loadingIcon;
private JLabel sort;
private String[] options = {SELECTION_SORT_TEXT, INSERTION_SORT_TEXT, MERGE_SORT_TEXT};
public Sorter()
{
setTitle("Sorter");
setSize(WIDTH, HEIGHT);
setLayout(new BorderLayout());
setDefaultCloseOperation(EXIT_ON_CLOSE);
createContents();
setVisible(true);
}
private void createContents()
{
//TODO: Implement
this.panel = new JPanel(new FlowLayout());
this.display = new JTextArea();
this.loadingIcon = new JLabel(new ImageIcon("loading.gif"));
this.sort = new JLabel("Sorting Algorithm");
this.sortButton = new JButton("Sort");
this.sortingAlgorithms = new JComboBox<>(options);
loadingIcon.setSize(25,25);
display.setBorder(new EmptyBorder(10,10,10,10));
panel.add(sort);
panel.add(sortingAlgorithms);
panel.add(sortButton);
panel.add(loadingIcon);
sortButton.addActionListener(new SortButtonListener());
loadingIcon.setVisible(false);
display.setEnabled(false);
setLayout(new BorderLayout());
add(panel, BorderLayout.NORTH);
add(display, BorderLayout.CENTER);
}
private class SortButtonListener implements ActionListener
{
private int[] arr;
private SortRunnable sr;
public void actionPerformed(ActionEvent e)
{
sr.run();
ExecutorService es = Executors.newSingleThreadExecutor();
//TODO: Finish Implementation
if(e.getSource() == sortButton)
{
sortingAlgorithms.setEnabled(false);
sortButton.setEnabled(false);
loadingIcon.setVisible(true);
display.setText("N\t\tRuntime (ms)");
}
arr = new int [2000];
for(int i = 0; i <= 8; i++)
{
arr = new int [(int) Math.pow(2, i) * 1000];
fillArr();
sr = new SortRunnable((String) sortingAlgorithms.getSelectedItem(), arr, Sorter.this);
es.execute(sr);
}
Thread sortContext = new Thread(new SortRunnable((String)
sortingAlgorithms.getSelectedItem(), arr, Sorter.this));
sortContext.start();
es.shutdown();
}
/*
These values are powers of 2 from 0 to 8, times 1000.
*/
private void fillArr()
{
Random r = new Random();
int n = 0;
for(int i=0; i<arr.length; ++i)
{
arr[i] = r.nextInt();
}
}
}
/*
The displayResult method is responsible for adding the provided sort runtime information to
the display. It should also check to see if the final sort runtime information is present. If so,
it should hide the loading gif and enable the JComboBox and sort button.
*/
public synchronized void displayResult(int n, long runtime)
{
//TODO: Implement
display.append("\n" + n + "\t\t" + runtime);
}
public static void main(String[] args)
{
new Sorter();
}
}
我不太关心上面的内容。我更关心如何在创建这些线程的 SortRunnable class 中创建我的线程。这是此 class 的预期结果。
此 class 包含用于计时和执行所选排序的代码。
• 您可以找到在排序的开始结束时调用 System.currentTimeMillis() 以获得其 运行 时间的区别。
• 在执行搜索之前在 Runnable 中调用 "Thread.yield()" 以确保 GUI 线程具有根据需要更新其显示所需的优先级。
• 排序完成后,应在 GUI 线程中更新显示。这可以通过在 Sorter 引用上调用 "displayResult" 方法来完成。此调用应在 Runnable 对象的 运行 方法中发生,作为参数传递给 SwingUtilities invokeLater 方法,如:
SwingUtilities.invokeLater(new Runnable()
{
@Override
public void run()
{
//call Sorter's displayResult method here
}
});
这是我需要帮助的代码。
import javax.swing.*;
public class SortRunnable implements Runnable
{
private String sortingAlgorithm;
private int[] arr;
private Sorter sorter;
public SortRunnable(String sortingAlgorithm, int[] arr, Sorter sorter)
{
this.sortingAlgorithm = sortingAlgorithm;
this.arr = arr;
this.sorter = sorter;
}
@Override
public void run()
{
Thread.yield();
if(sortingAlgorithm.equals(sorter.MERGE_SORT_TEXT))
{
MergeSort.mergeSort(arr);
}
Thread.yield();
if(sortingAlgorithm.equals(sorter.SELECTION_SORT_TEXT))
{
SelectionSort.sort(arr);
}
Thread.yield();
if(sortingAlgorithm.equals(sorter.INSERTION_SORT_TEXT))
{
InsertionSort.sort(arr);
}
SwingUtilities.invokeLater(new Runnable()
{
@Override
public void run()
{
Thread.yield();
sorter.displayResult(arr.length, System.currentTimeMillis());
//call Sorter's displayResult method here
}
});
}
}
我只需要有关插入和选择线程的帮助。谢谢!如果您想要他们的个人 classes 以便您可以看到他们里面有什么,请告诉我。
Thread sortContext = new Thread(new SortRunnable(*whatever args you need*));
sortContext.start();
应该可以解决问题,除非您尝试从新线程更新 ui。
SwingUtilities.invokeLater
将请求放入 Swing 的事件队列中进行处理 "at some point in the future"。 Runnable
在事件调度线程的上下文中出列并执行,这意味着您的排序是 运行 在与 UI 相同的线程中,并且将阻塞它直到它完成。
现在,事情变得非常复杂。 Swing 不是线程安全的(这意味着您不应该从事件调度线程上下文外部更新 UI)并且是单线程的,这意味着任何长 运行 或阻塞操作都会阻止 UI 已更新。
"long" 答案是,使用专为这项工作设计的 SwingWorker
。不过,你可以继续使用你的代码,只是有点乱。
您需要捕获更多详细信息,例如排序开始时间和排序结束时间。然后你需要计算这两个时间点之间的毫秒差。
您 "might" 有很多方法可以做到这一点,但是由于 Java 现在有一个不错的新 date/time API,您不妨开始使用它。
然后将此信息传回 UI,可能类似于...
public class SortRunnable implements Runnable
{
private String sortingAlgorithm;
private int[] arr;
private Sorter sorter;
public SortRunnable(String sortingAlgorithm, int[] arr, Sorter sorter)
{
this.sortingAlgorithm = sortingAlgorithm;
this.arr = arr;
this.sorter = sorter;
}
@Override
public void run()
{
LocalDateTime startTime = LocalDateTime.now();
MergeSort.mergeSort(arr);
LocalDateTime endTime = LocalDateTime.now();
long diff = ChronoUnit.MILLIS.between(startTime, endTime)
SwingUtilities.invokeLater(new Runnable()
{
@Override
public void run()
{
sorter.displayResult(arr.length, diff);
}
});
}
}
好的,下一个问题是您没有使用 ExecutorService
。
首先,它确实应该是一个实例字段,因为您不需要继续创建它的更多实例。
其次,你的逻辑无处不在,基本上你想...
- 创建
Sorter
的实例
- 填充数组
- 创建
SortRunnable
的实例
- 将
SortRunnable
提交给ExecutorService
以便它可以被执行...
也许更像...
private ExecutorService es = Executors.newSingleThreadExecutor();
public void actionPerformed(ActionEvent e)
{
fillArr();
Sorter sorter = null;
String algorthim = null;
if(e.getSource() == options[0])
{
// create the instance of Sorter to be used...
sorter = ...
algorthim = ...
}
if(e.getSource() == options[1])
{
// create the instance of Sorter to be used...
sorter = ...
algorthim = ...
}
if(e.getSource() == options[2])
{
// create the instance of Sorter to be used...
sorter = ...
algorthim = ...
}
if (sorter != null) {
SortRunnable sr = new SortRunnable(algorthim, arr, sorter)
es.submit(sr);
}
我创建这些线程的解决方案如下:
在 sortRunnable class 中:
public void run()
{
long store = System.currentTimeMillis();
if(sortingAlgorithm.equals(sorter.MERGE_SORT_TEXT))
{
MergeSort.mergeSort(arr);
}
if(sortingAlgorithm.equals(sorter.SELECTION_SORT_TEXT))
{
SelectionSort.sort(arr);
}
if(sortingAlgorithm.equals(sorter.INSERTION_SORT_TEXT))
{
InsertionSort.sort(arr);
}
SwingUtilities.invokeLater(new Runnable()
{
@Override
public void run()
{
sorter.displayResult(arr.length, System.currentTimeMillis()-store);
//call Sorter's displayResult method here
}
});
}
那是我创建主题的地方。
在我的另一个 class 上,我将它们放入如下:
private class SortButtonListener implements ActionListener
{
private int[] arr;
private SortRunnable sr;
public void actionPerformed(ActionEvent e)
{
ExecutorService es = Executors.newSingleThreadExecutor();
//TODO: Finish Implementation
if(e.getSource() == sortButton)
{
sortingAlgorithms.setEnabled(false);
sortButton.setEnabled(false);
loadingIcon.setVisible(true);
display.setText("N\t\tRuntime (ms)");
}
arr = new int [2000];
for(int i = 0; i <= 8; i++)
{
arr = new int [(int) Math.pow(2, i) * 1000];
fillArr();
sr = new SortRunnable((String) sortingAlgorithms.getSelectedItem(), arr, Sorter.this);
es.execute(sr);
}
es.shutdown();
}
private void fillArr()
{
Random r = new Random();
for(int i=0; i<arr.length; ++i)
{
arr[i] = r.nextInt();
}
}
}
要求其他方法执行的操作,但那是我放入主题的地方。