0

我用 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;
            }
        }
    }
}
4

2 回答 2

2

就 GUI 而言,您需要阅读有关Swing 并发的信息。简而言之,使用SwingWorker

请注意,您使用旧的 AWT 东西 (java.awt.EventQueue)。

于 2011-01-05T19:55:36.310 回答
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);
于 2011-01-05T19:48:33.413 回答