Lagujące wątki w java

0

Używam Eclipse na linuxie 16.04, problem jest taki, że przy odpaleniu programu okienkowego (korzysta z między innymi wątków i rysowania) czynności wykonywane w wątkach strasznie lagują. Okazuje się też, że po naciśnięciu dowolnego klawisza powraca płynność (znika po puszczeniu klawisza). Problem powtarza się w różnych projektach (dlatego nie wklejam kodu). Ten sam program odpalony na windowsie na tej samej wersji Eclipse działa świetnie. Jest jakiś mechanizm na linuxie którego nie znam? Jak usunać te lagi?

0

Oto kod: działa płynnie na windowsie, na linuxie płynnie przy przytrzymaniu guzika
klasa main:

package package1;

public class main1 {

	public static void main(String[] args) {
	new A();
	}

}

klasa A:

package package1;

import java.awt.BorderLayout;
import java.awt.Dimension;
import java.util.ArrayList;

import javax.swing.JFrame;

public class A {

	Options o;

	A() {
		o = new Options();

		o.myframe.setTitle("window");
		o.myframe.getContentPane().setPreferredSize(new Dimension(o.DIMENSION,o.DIMENSION));
		o.myframe.setSize(o.DIMENSION, o.DIMENSION);
		o.myframe.pack();
		
		o.myframe.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		o.myframe.setLayout(new BorderLayout());
		o.myframe.setVisible(true);
		
		
		new Draw(o);
		
	    ArrayList<Watek3> runnable = new ArrayList<Watek3>();
	    ArrayList<Thread> thread = new ArrayList<Thread>();
	    
		for (int i = 0; i < o.NUMBER; i++) {
			runnable.add(new Watek3(o,i));
			thread.add(new Thread(runnable.get(i)));
		}

		for (int i = 0; i < o.NUMBER; i++) {
			thread.get(i).start();
		}

	}

}

klasa Draw:

package package1;

import java.awt.Graphics;
import java.awt.Graphics2D;

import javax.swing.JPanel;

public class Draw extends JPanel {
	Options o;

	Draw(Options o) {
		this.o = o;
		o.myframe.add(this);
	}

	@Override
	public void paintComponent(Graphics g) {
		Graphics g2d = (Graphics2D) g;
		for(int i=0;i<o.NUMBER;i++) {
		g2d.drawImage(o.lista_img.get(i), o.x[i], o.y[i], this);
		g2d.drawLine(o.DIMENSION/2, 0, o.DIMENSION/2, o.DIMENSION);
		g2d.drawLine(0, o.DIMENSION/2, o.DIMENSION, o.DIMENSION/2);
		}
	}

	

}

klasa Options:

package package1;

import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;

import javax.imageio.ImageIO;
import javax.swing.JFrame;

public class Options {
	final int NUMBER = 13;
	final int DIMENSION = 700;
	JFrame myframe = new JFrame();
	BufferedImage img;
	int x[] = new int[NUMBER];
	int y[] = new int[NUMBER];
	int dx[] = new int[NUMBER];
	int dy[] = new int[NUMBER];
	ArrayList<BufferedImage> lista_img = new ArrayList<BufferedImage>();
	Options() {
		try {
			img = ImageIO.read(new File("images/qwe.png"));
		} catch (IOException e) {
			System.err.println("file error");
			e.printStackTrace();
		}
		
		for (int i = 0; i < NUMBER; i++) {
			x[i] = img.getWidth();
			y[i] = i*img.getHeight()+5*i;
			lista_img.add(img);
		}


	}

}

klasa Watek3:

package package1;

import java.util.Random;

public class Watek3 implements Runnable {
	Options o;
	int ind;
	int dx, dy;
	int jezeli[] = new int[8];
	boolean czy_reset = false;
	Random rand = new Random();
	Watek3(Options o, int ind) {
		this.o = o;
		this.ind = ind;
	}

	private void set_jezeli() {
		jezeli[0] = o.img.getWidth();
		jezeli[1] = o.DIMENSION - 2 * o.img.getHeight();
		jezeli[2] = o.DIMENSION - 2 * o.img.getWidth();
		jezeli[3] = o.DIMENSION - 2 * o.img.getHeight();
		jezeli[4] = o.DIMENSION - 2 * o.img.getWidth();
		jezeli[5] = o.img.getHeight();
		jezeli[6] = o.img.getWidth();
		jezeli[7] = o.DIMENSION - o.img.getHeight();
	}

	private void zamien(int zmiana) {
		jezeli[0] += zmiana;
		jezeli[1] -= zmiana;
		jezeli[2] -= zmiana;
		jezeli[3] -= zmiana;
		jezeli[4] -= zmiana;
		jezeli[5] += zmiana;
	}

	@Override
	public void run() {
		boolean is=false;
		int zmiana = 10;
		int speed= (ind*2+1);
		set_jezeli();
		for (;true;) {
			if (Math.sqrt(Math.pow(o.DIMENSION / 2 - o.x[ind], 2) + Math.pow(o.DIMENSION / 2 - o.y[ind], 2)) <= (Math.sqrt(o.img.getHeight()*o.img.getHeight()+o.img.getWidth()*o.img.getWidth())+1)) {
				do {
				dx=rand.nextInt()%o.NUMBER-o.NUMBER/2;
				dy=rand.nextInt()%o.NUMBER-o.NUMBER/2;
				}while(Math.sqrt(dx*dx+dy*dy)<=speed ||Math.sqrt(dx*dx+dy*dy)>=4*speed);
			
```	
				while(o.y[ind]<=o.DIMENSION-2*o.img.getHeight() && o.y[ind]>=o.img.getHeight() && o.x[ind]>=o.img.getWidth() && o.x[ind]<=o.DIMENSION-2*o.img.getWidth())
				{
					o.x[ind] += dx;
					o.y[ind] += dy;
					try {
						Thread.sleep(15);
					} catch (InterruptedException e) {
						System.err.println("pause error");
						e.printStackTrace();
					}

				}
				set_jezeli();
			}
			if (o.x[ind] <= jezeli[0] && o.y[ind] <= jezeli[1]) {
				if (is)
					zamien(zmiana);
				is = false;
				dx = 0;
				dy = speed;
			} else if (o.x[ind] <= jezeli[2] && o.y[ind] >= jezeli[3]) {
				dx = speed;
				dy = 0;
			} else if (o.x[ind] >= jezeli[4] && o.y[ind] >= jezeli[5]) {
				dx = 0;
				dy = -speed;
			} else if (o.x[ind] >= jezeli[6] && o.y[ind] <= jezeli[7]) {
				is = true;
				dx = -speed;
				dy = 0;
			}
			o.x[ind] += dx;
			o.y[ind] += dy;
			o.myframe.repaint();
			try {
				Thread.sleep(15);
			} catch (InterruptedException e) {
				System.err.println("pause error");
				e.printStackTrace();
			}
		}
	}
}
2

Wątek swing (rysujący w klasie Draw) nic nie wie o zmianach zachodzących w klasie Options, które robi wątek Watek3.
Brak jest jakiegoś synchronized, Volatile, CopyOnWriteArrayList - ogólnie dramat. Nic nie przechodzi przez barierę pamięci :-(

Kod jest tak nawalony, że trundo coś łatwo poprawić:
najmniejszym kosztem chyba da się zrobić to:
Opakuj te miejsca (i tylko te!) gdzie zmieniasz Options w SwingUtilities.invokeLater()

Przykład:

 while(o.y[ind]<=o.DIMENSION-2*o.img.getHeight() && o.y[ind]>=o.img.getHeight() && o.x[ind]>=o.img.getWidth() && o.x[ind]<=o.DIMENSION-2*o.img.getWidth())
            {
//zmiana
 SwingUtilities.invokeLater( () -> {
                o.x[ind] += dx;
                o.y[ind] += dy; 
} );
                try {
                    Thread.sleep(15);
                } catch (InterruptedException e) {
                    System.err.println("pause error");
                    e.printStackTrace();
                }

            }
            set_jezeli();
0

dzięki za pomoc, nie sądziłem że obsługa pamięci jest taka rozbudowana. Mam już następną rzecz do ogarnięcia xD
Natomiast wydaje mi się, że rozminęliśmy się z problemem, chodzi o to, że na windowsie jest płynność, na linuxie dopiero przy przytrzymaniu dowolnego klawisza, przygotowałem coś krótszego:

package package2;

public class TheFirstOne {

	public static void main(String[] args)
	{
		
		TheSecondOne two = new TheSecondOne();
		Thread wat = new Thread(two);
		wat.start();
	}

}
package package2;

import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;

public class TheSecondOne extends JPanel implements Runnable {
	int x = 0, y = 0;

	JFrame myframe = new JFrame("okno");

	TheSecondOne()
	{
		myframe.getContentPane().setPreferredSize(new Dimension(500, 500));
		myframe.pack();
		myframe.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		myframe.setLayout(new BorderLayout());
		myframe.setVisible(true);
		myframe.add(this);
	}

	public void paintComponent(Graphics g)
	{
		Graphics g2d = (Graphics2D) g;
		g2d.drawLine(0, 0, x, y);
	}

	@Override
	public void run()
	{
		for (int i = 0; i < 500; i++)
		{
			SwingUtilities.invokeLater(() -> {  //tutaj też to jest potrzebne?
				x = y++;
			});
			myframe.repaint();
			try
			{
				Thread.sleep(17);
			} catch (InterruptedException e)
			{
				System.err.println("pause error");
				e.printStackTrace();
			}
		}

	}
}

1

Nie próbowałem tego kompilować i odpalać, ale być może wciskanie klawisza daje systemowo generowane przemalowania i dlatego działa wtedy lepiej, a te przemalowania powodowane przez aplikacje przez swoją częstość są łączone w jedno raz na jakiś czas.
Do poczytania: http://www.oracle.com/technetwork/java/painting-140037.html

0

Stary, strzał w dziesiątkę. Zrobiłem osobny wątek który w nieskończoność wykonuje repaint() i usunąłem te funkcję z klasy Watek3. Działa pięknie, dzięki

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