我用Java编写了一个简单的应用程序,它从提供的html链接列表中下载特定图像。一切都工作正常,直到我添加了必须从HTML链接列表而不是一个链接下载的功能。我必须实现wait()和notify()方法,这迫使我改变方法。现在,下载工作正常,但下载过程中GUI不会更新。
我让第一个帖子从 HTML.java 等待,并在 DownloadImages.java 结束时通知它。为此我不得不调用buttonPressed类作为对象而不是线程,这就是为什么我认为我的GUI不会更新。
有没有办法在我的代码中简化或提高线程使用效率?
提前致谢。
这是我的代码的骨架:
/*Test.java*/
package my;
import java.util.logging.Level;
import java.util.logging.Logger;
public class Test extends javax.swing.JFrame {
public static buttonPressed bp;
public static boolean alldone;
/** Creates new form Test */
public Test() {
initComponents();
}
public static class buttonPressed implements Runnable {
Thread t1, t2;
buttonPressed() {
t1 = new Thread(this, "downloadAction");
t1.start();
}
public void suspendThread() {
System.out.println("suspended");
alldone = false;
}
public synchronized void resumeThread() {
System.out.println("resumed");
alldone = true;
notify();
}
public void run() {
String[] len = new String[]{/*list of urls*/};
for (int i = 0; i < len.length; i++) {
System.out.println("going times: " + i);
t2 = new Thread(new HTML(), "HTMLthread");
t2.start();
synchronized (this) {
while (!alldone) {
try {
wait();
} catch (InterruptedException ex) {
Logger.getLogger(Test.class.getName()).log(Level.SEVERE, null, ex);
}
}
}
}
}
}
private void downloadActionPerformed(java.awt.event.ActionEvent evt) {
bp = new buttonPressed();
try {
bp.t1.join();
} catch (InterruptedException e) {
System.out.println("Main Thread: interrupted");
}
}
public static void main(String args[]) {
java.awt.EventQueue.invokeLater(new Runnable() {
public void run() {
new Test().setVisible(true);
}
});
}
private javax.swing.JButton download;
public static javax.swing.JProgressBar progress;
}
/*HTML.java*/
package my;
import java.util.ArrayList;
class HTML implements Runnable {
private Thread t3;
public HTML() {
Test.bp.suspendThread();
}
public void run() {
downloadHTML();
ArrayList xyz = parseHTML();
t3 = new Thread(new DownloadImages(xyz), "DownDecrypt");
t3.start();
}
private void downloadHTML() {
// Downloads the HTML file
}
private ArrayList parseHTML() {
// Parses the HTML file and gets links to images
return new ArrayList();
}
}
/*DownloadImages.java*/
package my;
import java.io.BufferedInputStream;
import java.io.ByteArrayOutputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLConnection;
import java.util.ArrayList;
import java.util.logging.Level;
import java.util.logging.Logger;
class DownloadImages implements Runnable {
static int current = 0, previous = 0;
static boolean speedFlag;
ArrayList<String> links = new ArrayList<String>();
private Thread t4;
public DownloadImages(ArrayList param1) {
this.links = param1;
speedFlag = true;
}
public void run() {
t4 = new Thread(new getSpeed(), "getSpeed");
t4.start();
download(links);
}
private void download(ArrayList<String> param1) {
String[] imgurl = new String[param1.size()];
URLConnection conn = null;
InputStream is = null;
ByteArrayOutputStream bais = null;
int prog;
for (int i = 0; i < param1.size(); i++) {
current = 0;
imgurl[i] = param1.get(i);
try {
conn = new URL(imgurl[i]).openConnection();
int fsize = conn.getContentLength();
is = new BufferedInputStream(conn.getInputStream());
bais = new ByteArrayOutputStream();
byte[] byteChunk = new byte[1024];
int n;
while ((n = is.read(byteChunk)) > 0) {
bais.write(byteChunk, 0, n);
current = current + 1024;
prog = (int) (current * 100.0 / fsize);
Test.progress.setValue(prog);
}
} catch (MalformedURLException ex) {
Logger.getLogger(DownloadImages.class.getName()).log(Level.SEVERE, null, ex);
} catch (IOException e) {
e.printStackTrace();
} finally {
if (is != null) {
try {
is.close();
} catch (IOException ex) {
Logger.getLogger(DownloadImages.class.getName()).log(Level.SEVERE, null, ex);
}
}
}
byte[] imgBytes = bais.toByteArray();
try {
FileOutputStream fos = new FileOutputStream(i + ".jpg");
fos.write(imgBytes);
fos.flush();
fos.close();
} catch (FileNotFoundException ex) {
System.out.println("FileNotFoundException : " + ex);
} catch (IOException e) {
e.printStackTrace();
}
}
speedFlag = false;
// Resume the thread to start downloading the next link
Test.bp.resumeThread();
}
private static class getSpeed implements Runnable {
int kbytesPerSecond;
private final int fireTime;
public getSpeed() {
fireTime = 1000;
}
public void run() {
while (speedFlag) {
try {
Thread.sleep(fireTime);
} catch (InterruptedException ex) {
Logger.getLogger(getSpeed.class.getName()).log(Level.SEVERE, null, ex);
}
kbytesPerSecond = (((current - previous) / 1024) / (fireTime / 1000));
System.out.println(kbytesPerSecond);
previous = current;
}
}
}
}
答案 0 :(得分:2)
就GUI而言,您需要阅读Swing concurrency。简而言之,请使用SwingWorker。
请注意你使用旧的AWT东西(java.awt.EventQueue)。
答案 1 :(得分:0)
我建议你有一个像Executors.newCachedThreadPool这样的ExecutorService并将任务提交给它。收集Future对象,以便您知道它们何时完成。这比在整个地方创建线程更有效和可管理。
你可以只拥有一个像
这样的游泳池static final ExecutorService POOL = Executors.newCachedThreadPool();
提交任务
POOL.submit(new Callable<Void>() {
public Void call() throws InterruptedException {
while (speedFlag) {
Thread.sleep(1000);
kbytesPerSecond = (current - previous) / 1024;
System.out.println(kbytesPerSecond);
previous = current;
}
}
});
重复任务更好的方法是使用预定的执行程序服务。
static final ScheduledExecutorService POOL = Executors.newScheduledThreadPool(4);
Future task = POOL.scheduleAtFixedRate(new Runnable() {
public void run() {
kbytesPerSecond = (current - previous) / 1024;
System.out.println(kbytesPerSecond);
previous = current;
}
}, 1, 1, TimeUnit.SECONDS);
// to end the task
task.cancel(false);