使Java中的线程使用效率更高

时间:2011-01-05 19:44:29

标签: java multithreading wait notify

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

2 个答案:

答案 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);