Aktualizacja ArrayList z wielu wątków.

0

Piszę program, w którym chce zastosować takie rozwiązanie:

Jeden wątek sprawdza co 15 sekund czy zaistniał określony warunek.

Jeśli zaistnieje warunek to program uruchomi osobny wątek w którym wykona 200 zrzutów ekranu co 50ms i doda je do ArrayListy.

Kolejny wątek będzie sprawdzał czy lista jest pusta,
jeśli pusta to zaśnie na kolejne 30sekund,
jeśli nie to co sekundę pobierze pierwszy element listy, zapisze go do pliku i usunie z listy.

Chodzi mi o to żeby, czas dostępu do dysku oraz zapisu nie wpływał na odstęp czasu między zrzutami ekranu.

Pytania:

  1. Czy jeśli jeden wątek usuwa pierwszy element listy a inny wątek dodaje element na końcu listy to czy powinno się zastosować rozwiązanie podobne jak w temacie:
    http://4programmers.net/Forum/Newbie/211036-bezpieczny_dostep_do_arraylist_z_wielu_watkow_-synchronized
synchronized (scrCaptures) {
                        scrCaptures.remove(0);
                    };

lub może jakieś inne rozwiązanie, jakie?

  1. Czy jest sens wstrzymywać wątek zapisujący pliki na dysku na 1 sekundę między zapisami?

  2. Czy wątki stosować w taki sposób czy są może jakieś lepsze rozwiązania?

Poniżej umieściłem kod programu.

package scrCapt;

import java.awt.AWTException;
import java.awt.Rectangle;
import java.awt.Robot;
import java.awt.Toolkit;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.util.ArrayList;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.imageio.ImageIO;
import javax.swing.Timer;
import static scrCapt.Main.czyJestSpelnionyWarunek;
import static scrCapt.Main.scrCaptures;

public class Main {

    static ArrayList<BufferedImage> scrCaptures = new ArrayList<>();
    static Boolean czyJestSpelnionyWarunek = false;

    public static void main(String[] args) {
        new Thread(new SaveImage()).start();
        new SprawdzajWarunek().sprawdzajWarunek.start();
    }
}

class SprawdzajWarunek {
    Timer sprawdzajWarunek = new Timer(15000, new ActionListener() {
        @Override
        public void actionPerformed(ActionEvent ex) {
            if (czyJestSpelnionyWarunek) {
                new Thread(new TakeCaptures()).start();
            }
        }
    });
}

class TakeCaptures implements Runnable {

    @Override
    public void run() {
        for (int i = 0; i < 200; i++) {
            try {
                BufferedImage capture = screenCapture();
                scrCaptures.add(capture);
                Thread.sleep(50);
            } catch (InterruptedException ex) {
                Logger.getLogger(SaveImage.class.getName()).log(Level.SEVERE, null, ex);
            } catch (AWTException ex1) {
                Logger.getLogger(TakeCaptures.class.getName()).log(Level.SEVERE, null, ex1);
            }
        }
    }

    private BufferedImage screenCapture() throws AWTException {
        Robot robot = new Robot();
        int width = (int) Toolkit.getDefaultToolkit().getScreenSize().getWidth();
        int height = (int) Toolkit.getDefaultToolkit().getScreenSize().getHeight();
        Rectangle screenRct = new Rectangle(0, 0, width, height);
        BufferedImage snapShotImage = robot.createScreenCapture(screenRct);
        return snapShotImage;
    }
}

class SaveImage implements Runnable {

    @Override
    public void run() {
        while (true) {
            if (scrCaptures.size() == 0) {
                try {
                    Thread.sleep(30000); 
                // usypiam wątek na np. 30sek.
                } catch (InterruptedException ex1) {
                }
            } else {
                try {
                    BufferedImage image = scrCaptures.get(0);
                    saveImage(image, "c:/captures");
                    scrCaptures.remove(0);
                    Thread.sleep(1000);
        // nie jestem pewny czy ma sens usypianie tego watku na 1sek
        
                } catch (InterruptedException ex) {
                    Logger.getLogger(SaveImage.class.getName()).log(Level.SEVERE, null, ex);
                } catch (IOException ex) {
                    Logger.getLogger(SaveImage.class.getName()).log(Level.SEVERE, null, ex);
                }
            }
        }
    }

    private void saveImage(BufferedImage image, String path) throws IOException {
        int fileNumber = new java.io.File(path).listFiles().length;
        path += "capture_" + fileNumber + ".bmp";
        ImageIO.write(image, "bmp", new java.io.File(path));
    }
}

0

Zamiast ArrayList użyj BlockingDeque, czyli kolejki do której można odwołać się od przodu i od tyłu :)

1 użytkowników online, w tym zalogowanych: 0, gości: 1