我花了好几个小时试图找出一项实验室练习的要求。
计划摘要
类PrimeSeekerTask
生成范围之间的质数。PrimeSeekerDisplay
是显示在PrimeSeekerTask
中完成的工作的类。
PrimeSeekerTask应该在后台执行“大量”计算。我需要将SwingWorker
扩展为PrimeSeekerTask
。
在程序运行期间,应该有PrimeSeekerTask
的多个实例执行一小部分计算。我必须使用ExecutionService
。
另外,该程序应在单击开始按钮时启动,并在单击取消按钮时中断。
当我将任务作为单个背景SwingWorker
运行时,它工作正常(如本屏幕快照所示)
但是程序规范是我应该运行许多SwingWorker
对象。
我的问题
当我尝试使用ExecutionService
时,程序挂起并消耗了几乎100%的CPU,笔记本电脑开始哭了。对于较小的数字,我会找到错误的百分比和质数数值。我猜有些同步错误,但我认为Atomic
可以解决其中一些问题?
我的取消按钮不会中断任务。
任何帮助将不胜感激。
下面是我的真实尝试(为了使代码更短,我删除了导入)
public class PrimeSeekerDisplay extends JFrame
implements ActionListener, PropertyChangeListener {
private JLabel topLabel;
private JTextArea textArea;
private JProgressBar progressBar;
private JButton startButton;
private JButton cancelButton;
private JLabel primesFoundLabel;
private final long max;
private final long chunkSize;
PrimeSeekerTask task = null;
private final int THREAD_NUMBER = 9;
ExecutorService executorService = Executors
.newFixedThreadPool(THREAD_NUMBER);
/**
*
*/
private static final long serialVersionUID = 6602966318374691217L;
/**
*
*/
public PrimeSeekerDisplay(final long max, final long chunkSize) {
super("Prime Seeker");
this.max = max;
this.chunkSize = chunkSize;
initGui();
}
/*
* initGui() creates all the components and lays them on the display
*/
private final void initGui() {
// the top label
topLabel = new JLabel("Primes in [1.." + String.valueOf(max) + "]");
final JPanel topPanel = new JPanel();
topPanel.add(topLabel);
topPanel.setBorder(new EmptyBorder(5, 5, 5, 5));
// the text area
final JScrollPane textPane = createTextArea();
// the progress bar
progressBar = new JProgressBar(0, 100);
progressBar.setStringPainted(true);
progressBar.setBorder(BorderFactory.createLineBorder(Color.BLACK));
// the buttons and items in the status pane
startButton = createButton("Start");
// enable this at the beginning of program.
// This will be disabled when clicked
startButton.setEnabled(true);
cancelButton = createButton("Cancel");
// Disable cancel before program starts.
// Once program starts, this will be enabled
cancelButton.setEnabled(false);
// update this with number of primes found.
// only print something here when atleast a prime is found
primesFoundLabel = new JLabel();
primesFoundLabel.setEnabled(false);
final JPanel statusPanel = new JPanel(new FlowLayout(FlowLayout.LEFT));
statusPanel.setBorder(new EmptyBorder(10, 0, 0, 0));
statusPanel.add(startButton);
statusPanel.add(cancelButton);
statusPanel.add(primesFoundLabel);
// Jpanel to hold all components
final JPanel displayPanel = new JPanel();
displayPanel.setLayout(new BoxLayout(displayPanel, BoxLayout.Y_AXIS));
// add components to the display panel
displayPanel.add(topPanel);
displayPanel.add(textPane);
displayPanel.add(progressBar);
displayPanel.add(statusPanel);
displayPanel.setBorder(new EmptyBorder(10, 10, 10, 10));
// add the displayPanel to the frame
add(displayPanel);
setLocationRelativeTo(null);
setDefaultCloseOperation(EXIT_ON_CLOSE);
pack();
}
/**
* Create the text area embedded inside a ScrollPane
*
* @return a JScrollPane object
*/
private JScrollPane createTextArea() {
textArea = new JTextArea(8, 40);
textArea.setMargin(new Insets(5, 5, 5, 5));
textArea.setLineWrap(true);
textArea.setWrapStyleWord(true);
textArea.setEditable(false);
textArea.setLineWrap(true);
textArea.setWrapStyleWord(true);
final JScrollPane scrollPane = new JScrollPane(textArea);
return scrollPane;
}
/**
* A method for creating a JButton
*
* @param text The text to display on the button This value in lower
* case is also the actionCommand
* @return A JButton with text, actionCommand, and action listener set
*/
private JButton createButton(final String text) {
final JButton button = new JButton(text);
button.setActionCommand(text.toLowerCase());
button.addActionListener(this);
return button;
}
/*
* (non-Javadoc)
*
* @see java.awt.event.ActionListener#actionPerformed(java.awt.event.
* ActionEvent)
*/
@Override
public void actionPerformed(ActionEvent e) {
if (e.getActionCommand().equalsIgnoreCase("start")) {
startButton.setEnabled(false);
cancelButton.setEnabled(true);
textArea.setText(null);
primesFoundLabel.setText("Nothing found yet");
// ####### Attempt to run many PrimeSeekerTasks fails ######
// ****** i need help here and how to cancel the process///
/*
int chunk = (int) (max / chunkSize);
System.out.println("chunk => " + chunk);
int remainder = (int) (max % chunkSize);
for (int index = 0; index < chunk; index++) {
final long lower = index * chunkSize;
final long upper = (index == chunk - 1
? (lower + remainder + chunkSize)
: (lower + chunkSize));
System.out.println("Index: " + index + " Lower: " + lower
+ " upper: " + upper);
PrimeSeekerTask primer = new PrimeSeekerTask(lower, upper);
primer.addPropertyChangeListener(this);
executorService.submit(primer);
}
*/
// =======
//Running this works very well but it is not according to
// program specs
// ===========
task = new PrimeSeekerTask(1, max);
task.addPropertyChangeListener(this);
task.execute();
}
if (e.getActionCommand().equalsIgnoreCase("cancel")) {
if (task != null) {
task.cancel(true);
}
startButton.setEnabled(true);
cancelButton.setEnabled(false);
//executorService.shutdownNow();
}
}
/**
* PrimeSeekerTask generatates prime numbers in a range and updates the
* progressBar, textArea and primesFoundLabel
*
*
* @author longb
*
*/
private class PrimeSeekerTask extends SwingWorker<String, String> {
private final long lowerRange;
private final long upperRange;
private final AtomicInteger progressMade = new AtomicInteger(0);
private final AtomicLong primesFound = new AtomicLong(0);
/**
* @param upperRange
* @param lowerRange
*/
public PrimeSeekerTask(final long lowerRange, final long upperRange) {
super();
this.lowerRange = lowerRange;
this.upperRange = upperRange;
}
/*
* (non-Javadoc)
*
* @see javax.swing.SwingWorker#doInBackground()
*/
@Override
protected String doInBackground() throws Exception {
while (!isCancelled()) {
for (long lower = lowerRange; lower < upperRange; lower++) {
if (isPrime(lower)) {
primesFound.getAndIncrement();
publish(String.valueOf(lower));
primesFoundLabel.setText(
"Primes found: " + primesFound.intValue());
}
progressMade.getAndIncrement();
int progress = (int) (100 * (progressMade.intValue() + 1)
/ upperRange);
setProgress(progress);
}
}
return "\n";
}
/*
* (non-Javadoc)
*
* @see javax.swing.SwingWorker#process(java.util.List)
*/
@Override
protected void process(List<String> chunks) {
for (String string : chunks) {
textArea.append(string + ", ");
}
}
/*
* (non-Javadoc)
*
* @see javax.swing.SwingWorker#done()
*/
@Override
protected void done() {
startButton.setEnabled(true);
cancelButton.setEnabled(false);
}
}
private boolean isPrime(final long number) {
final long limit = (long) Math.sqrt(number) + 1;
if (number < 2) {
return false;
}
for (long i = 2; i < limit; ++i) {
if ((number % i) == 0) {
return false;
}
}
return true;
}
/*
* (non-Javadoc)
*
* @see java.beans.PropertyChangeListener#propertyChange(java.beans.
* PropertyChangeEvent)
*/
@Override
public void propertyChange(PropertyChangeEvent evt) {
if ("progress".equalsIgnoreCase(evt.getPropertyName())) {
int progress = (int) evt.getNewValue();
progressBar.setValue(progress);
}
}
}
//在Run.java中
public class Run {
/**
*
*/
public Run() {
// TODO Auto-generated constructor stub
}
/**
* @param args
*/
public static void main(String[] args) {
if (args.length == 3) {
for (int i = 0; i < args.length; i++) {
System.out.println("arg#" + i + " : " + args[i]);
}
try {
long max = Integer.valueOf(args[1]);
long chunksize = Integer.valueOf(args[2]);
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
PrimeSeekerDisplay display = new PrimeSeekerDisplay(max,
chunksize);
display.setVisible(true);
}
});
} catch (Exception e) {
e.printStackTrace();
}
} else {
System.err.println("\nUsage: lab8 maxValue chunkSize\n");
}
}
}
提前致谢。
最佳答案
这个答案与发布的第二个问题有关:“我的取消按钮不会中断任务”。
您有一个while
循环,该循环应该在isCancelled()
返回false时停止:
`while (! isCancelled())`
问题是,它后面是一个
for
循环。仅当for
循环完成时才评估停止条件。要克服它,只需添加
if (isCancelled() ) { break;}
在
for
循环中。第一个问题需要更多调查。
(请注意one question per post policy)