One of my applications paints objects to a screen by reading an array List:
simple code summary:
#Override
public synchronized void paintComponent(Graphics g) {
for(Object gO:paintList) {
g.drawImage( gO.getObjImage(), gO.getXLoc(), gO.getYLoc(), outer.getTransparent(), null);
}
}
The problem is I add more objects every time the user clicks the mouse, so if if the user clicks fast enough, I can cause the program painting to stutter since it cannot read while it is writing (the arrayList is synchronized). What is the common practice developers use to deal with this concurrency issue?
edit: here is the code that calls the repaint:
byte ticks = 0;
while(true) {
currentTime = System.nanoTime();
if(ticks == 25) {
drawPanel.repaint();
ticks = 0;
} else if (ticks%5 == 0) {//if ticks is a multiple of 5 (5,10,15,...)
drawPanel.operations();
ticks++;
} else if(ticks < 25) {
ticks++;
}
try {
/*
Refer to: 'http://stackoverflow.com/questions/1036754/difference-between-wait-and-sleep'
on differences between Thread.sleep() and wait()
*/
wait(1);//old timings: (long)(refreshRate*1000)
} catch (InterruptedException ex) {
Logger.getLogger(DeathWish.class.getName()).log(Level.SEVERE, null, ex);
}
//Debugging
//System.out.println(ticks);
currentTime = System.nanoTime();
*where operations() calculates changes in 'paintable' object's properties, removes objects that meet certain conditions and adds new objects to the paint list. Logically to me, the adding and writing should be separated?
I can post the operations() method, if there isn't enough information, but I'm trying not to post huge sections of code so it is easier to interpret.
I guess you're getting things a bit wrong with synchronization :
ArrayList is a list implemented without synchronization
A synchronized method means that only 1 Thread at a time can access the method, but the variables inside your function are not synchronized at all
What you want, is to have your list temporary synchronized.
You could do something like that :
#Override
public void paintComponent(Graphics g) {
synchronized(paintList) {
for(Object gO:paintList) {
g.drawImage( gO.getObjImage(), gO.getXLoc(), gO.getYLoc(), outer.getTransparent(), null);
}
}
}
and in the code adding objects yo your list do somewhat the same.
EDIT from here :
If you want to remove all the concurrency problems between the add thread and the paint Thread, here's how you could do :
in the method to add images :
public synchronized void addImage(...) {
Something newImage = .....
List<Something> newPaintList = new ArrayList<>(paintList.size() + 1);
newPaintList.addAll(paintList);
newPaintList.add(newImage);
paintList = newPaintList;
}
And in the paint method, remove the synchronization part.
#Override
public void paintComponent(Graphics g) {
for(Object gO:paintList) {
g.drawImage( gO.getObjImage(), gO.getXLoc(), gO.getYLoc(), outer.getTransparent(), null);
}
}
With this, you won't have any concurrency between the reads and the writes, since the only operation done on paintList is reads.
The addImage should be synchronized to avoid two different Threads adding images at the same time, which could make one addImage ignored.
Related
I am using a Thread to do some calculations related to the app that need to be done simultaneously but this Thread causes the FPS to drop (logically) and I wanted to know how to resolve the issue as the Thread is not doing any heavy calculations at all. Here is the code where I implement the Thread and the Thread itself.
incrementMass = new IncrementMass();
incrementMass.start();
// I added some extra functionality to the InputProcessor but I assume that is irrelevant
if(InputProcessor.isButtonUp() && InputProcessor.getButtonLetGo() == RIGHT && !isJustPressed) {
isJustPressed = true;
try {
incrementMass.join();
} catch(InterruptedException e) {
e.printStackTrace();
}
planets.add(new Planet(10, m, mouseOnWorld2.x, mouseOnWorld2.y));
} else if(Gdx.input.isButtonJustPressed(RIGHT)) {
isJustPressed = false;
incrementMass.restart();
}
The Thread:
/**
* Thread to increment the mass in a while loop.
*/
public class IncrementMass extends Thread {
/**
* Increments the mass when started.
*/
#Override
public void run() {
super.run();
while(Gdx.input.isButtonPressed(Input.Buttons.RIGHT)) {
MainScreen.m += 100;
System.out.println(MainScreen.m);
}
}
/**
* Resets the mass so the whole thing starts over (for the creation of a new planet)
*/
public void restart() {
MainScreen.m = 100000;
}
}
All this is called in the render() function of my Screen by the way.
I have one idea as to what is causing this: Every frame I create a new Thread which is not optimal but everything else I tried failed to actually perform my calculations correctly. It definitely solves the FPS problem to have the initiation of the Thread and the ´start()´ function in the constructor of my Screen but that for some reason messes with the incrementing of the mass and makes it a fixed value: the value I reset it to in ´restart()´
I've been trying to solve this but I'm baffled so here I am.
As said in the comment, there was no function for isButtonJustUp() which made it not be able to run sequentially. Therefore I made a Thread so that it was sequential which is not a good implementation of Threads. I've come up with a solution:
if(Gdx.input.isButtonPressed(RIGHT)) {
m += 100;
} else if(InputProcessor.isButtonJustUp() && InputProcessor.getButtonLetGo() == RIGHT) {
planets.add(new Planet(10, m, mouseOnWorld2.x, mouseOnWorld2.y));
m=0;
}
I haven't made isButtonJustUp() yet but it is the best way rather than implementing an unnecessary Thread.
I am writing a Processing project (Processing is based on Java). I want to run the code inside one thread in another thread (the main thread).
//This method runs in the main thread
public void draw() {
}
//This is a callback that runs in a separate thread
void addTuioObject(TuioObject tobj) {
rect(0, 0, 20, 10);
}
The rect(0,0,20,10) does not run in the main thread (it is supposed to draw a rectangle on the screen). I suppose this is because it runs in a separate thread. How would I make this code run in the main thread?
Most common solution is to provide state variable and make draw() method to draw according to current state.
State variable may be as simple as single primitive type (boolean for example) or complex object.
Idea is that:
main thread (animation thread in processing) calls draw() for each frame, and draw() method uses state variable to paint screen.
other thread can modify state, but has nothing to do with drawing or pixels...
Consider 2 examples:
1) simple state (single boolean variable)
// state variable
private boolean shouldPaint;
void draw() {
background(0);
fill(200);
rect(10, 10, 30, 30);
if (shouldPaint) {
rect(50, 10, 30, 30);
}
}
// called in other thread
someMethod() {
shouldPaint = !shouldPaint;
}
2) more complex state
// state variable
private PVector[] vectors = new PVector[5];
private int index = 0;
void draw() {
background(0);
fill(200);
for (PVector v : vectors) {
if (v != null) {
rect(v.x, v.y, 10, 10);
}
}
}
// called by other thread
void someMethod() {
if (index >= vectors.length) {
index = 0;
}
// vector for current index value
PVector v = vectors[index];
if (v == null) {
vectors[index] = new PVector(index * 20, index * 20);
} else {
vectors[index].add(new PVector(30, 0));
}
index++;
}
Remember that draw() method is called 60 times per second (if default frame rate). Each draw() execution modifies screen (pixel) buffer. If you want to disapper unwanted objects from screen you should start draw() method with background(color) that clears whole buffer.
There are several ways to do this. Depending on what you actually want to achieve. If you're working with awt or swing your drawing code should actually not run in the main thread but in the awt thread instead. You can dispatch work to that thread for example using SwingUtils. If you really want to execute the code in another thread (e.g. main) you need to make sure that the target thread will be able to pickup new work e.g. from a queue.
So here is my issue, I have an ArrayList, it contains all of the entities that should be rendered to the screen.
It does so like this with a foreach loop.
for (Entity e : entities) {
g.fillRect(x, y, w, h);
}
This works perfectly fine with no errors when it is populated with a lower numbers of values such as 50. That is, the size of the list is 50. However when it is something like 1,000 it throws a ConcurrentModificationException and crashes the app.
I know that the exception means the list has been modified whilst iterating through it, but in that loop is never actually does anything to the list. The list is accessed elsewhere to update things, but shouldn't the foreach loop finish before something else happens that modifies the list?
The list is modified in an update method which updates entities.
The zombies are enemies in a sense and survivors are AI. When a zombie collides with an AI it removed the survivor and replaces it with a survivor. This is the only place the lists are modified.
This all works perfectly when it is dealing with a small number of entities, however with a larger number it crashes.
public void update(double delta) {
for (Zombie z : zombies) {
z.update(delta);
}
for (Survivor s : survivors) {
s.update(delta);
}
List<Survivor> toRemove = new ArrayList<Survivor>();
List<Zombie> toAdd = new ArrayList<Zombie>();
for (Survivor s : survivors) {
for (Zombie z : zombies) {
if (z.collides(s)) {
toAdd.add(new Zombie(s.position, this, zms));
toRemove.add(s);
}
}
}
for (Survivor s : toRemove) {
survivors.remove(s);
}
for (Zombie z : toAdd) {
zombies.add(z);
}
}
public void update(double delta)
This method sounds like one that's being called by an engine of some sort, which is almost certainly in another thread.
for (Entity e : entities) {
g.fillRect(x, y, w, h);
}
This is running in your swing thread, which is separate.
When you have a few number of entities it is likely that this operation may complete atomically. When you have a much larger number of entities, you have a much higher chance of swapping into another thread to do work in the middle of drawing the entities.
The fix(I'm assuming zombies and survivors are entities):
synchronized(entities)
{
for (Survivor s : toRemove) {
survivors.remove(s);
}
for (Zombie z : toAdd) {
zombies.add(z);
}
}
And in your paint:
synchronized(entities)
{
for (Entity e : entities) {
g.fillRect(x, y, w, h);
}
}
This will ensure that only 1 thread can be in one of the synchronized blocks at a time, forcing them to happen separate from eachother
EDIT: This has a possibility of painting a frame after a collision has occurred. If your frame rate is high enough this will be completely unnoticeable. If you do start to notice it, then you may need to do a little bit more work so that once an update starts, a paint will not start until completely done.
To avoid synchronization, you should think about using the list read-only.
That is, in update(), don't remove from the list, but copy survivors to a new list, then add zombies to that new list. Finally, you can replace the reference to the old list with one to the new list.
This only requires synchronization on the object that holds this reference. But because the replacement of a reference is really cheap, synchronization wouldn't cause another trhread to wait too long.
// pseudo code
newList = update(entities); // takes some time
synchronized (this) {
entities = newList; // is quasi-immediate
}
Don't forget to make the getter for entities synchronized, too, and access entities only through the getter.
At first I did this:
public SpaceCanvas(){
new Thread(new Runnable () {//this is the thread that triggers updates, no kidding
int fcount = 0;
#Override
public void run() {
System.out.println("Update thread started!");
while(!Thread.interrupted()){
fcount++;
while(players.iterator().hasNext()){
players.iterator().next().update(fcount);
}
while(entities.iterator().hasNext()){
entities.iterator().next().update(fcount);
}
System.out.println("About to paint");
repaint();
System.out.println("Done with paints");
try {
Thread.sleep(500);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}).start();
players.add(new LocalPlayer(0, 9001, 0, 0, 0, 0, this, null));
}
in the initializer of a thing I call a SpaceCanvas.
However, that doesn't allow the canvas, and therefore the applet it is within, to be created, because the Thread doesn't actually run asynchronously. Then, I replaced ".start()" with ".run()" and the thread only ran once, but the SpaceCanvas initialized perfectly.
What did I do wrong, and how do I fix this?
I'm not sure this sort of code works the way you expect it to:
while(players.iterator().hasNext()){
players.iterator().next().update(fcount);
players.iterator() gets a new iterator for the players collection. If there are 0 items in the collection then it will be false but if there are any items, you will be in an infinite loop, creating a new iterator each time. The iterator() call inside of players generates another new iterator object as well.
I think you should doing something like:
Iterator iterator = players.iterator();
while (iterator.hasNext()) {
iterator.next().update(fcount);
}
This is the same with your entities loop as well. A better pattern (as of Java 5) is to use the for loop:
for (Player player : players) {
player.update(fcount);
}
Also, if multiple threads are accessing these collections, they have to be somehow synchronized. You can either use a concurrent collection or you have to make sure every access (read and write) is within a synchronized block.
synchronized (players) {
for (Player player : players) {
player.update(fcount);
}
}
...
// down in the outer thread
synchronized (players) {
players.add(new LocalPlayer(0, 9001, 0, 0, 0, 0, this, null));
}
Obviously the entities will need to be synchronized in the same manner.
In this millennium, use Swing (JApplet/JPanel) rather than AWT (Applet/Canvas)
When using Swing, establish a Swing Timer that calls repaint() every 500 msec.
(When using Swing/Timer) Don't call Thread.sleep(n) on the EDT (Event Dispatch Thread).
..can you draw on a JPanel?
Sure thing. To do so, override the paintComponent(Graphics) method. You might also extend a JComponent and do the same, but there are some quirks to dealing with a JComponent that make the JPanel the better choice to extend.
On the other hand, there is another approach entirely.
Create a BufferedImage of the size required for whatever custom graphic is needed.
Add the image to an ImageIcon.
Add the icon to a JLabel.
Add the label to the GUI.
On each Timer action.
Call image.getGraphics() to obtain the drawing surface.
Replicate what you might have done in paint() or paintComponent()
(If needed) erase all previous drawing.
Draw the current custom rendering.
dispose() of the Graphics instance of the image.
call label.repaint()
I am writing a multithreaded parser.
Parser class is as follows.
public class Parser extends HTMLEditorKit.ParserCallback implements Runnable {
private static List<Station> itemList = Collections.synchronizedList(new ArrayList<Item>());
private boolean h2Tag = false;
private int count;
private static int threadCount = 0;
public static List<Item> parse() {
for (int i = 1; i <= 1000; i++) { //1000 of the same type of pages that need to parse
while (threadCount == 20) { //limit the number of simultaneous threads
try {
Thread.sleep(50);
} catch (InterruptedException ex) {
ex.printStackTrace();
}
}
Thread thread = new Thread(new Parser());
thread.setName(Integer.toString(i));
threadCount++; //increase the number of working threads
thread.start();
}
return itemList;
}
public void run() {
//Here is a piece of code responsible for creating links based on
//the thread name and passed as a parameter remained i,
//connection, start parsing, etc.
//In general, nothing special. Therefore, I won't paste it here.
threadCount--; //reduce the number of running threads when current stops
}
private static void addItem(Item item) {
itenList.add(item);
}
//This method retrieves the necessary information after the H2 tag is detected
#Override
public void handleText(char[] data, int pos) {
if (h2Tag) {
String itemName = new String(data).trim();
//Item - the item on which we receive information from a Web page
Item item = new Item();
item.setName(itemName);
item.setId(count);
addItem(item);
//Display information about an item in the console
System.out.println(count + " = " + itemName);
}
}
#Override
public void handleStartTag(HTML.Tag t, MutableAttributeSet a, int pos) {
if (HTML.Tag.H2 == t) {
h2Tag = true;
}
}
#Override
public void handleEndTag(HTML.Tag t, int pos) {
if (HTML.Tag.H2 == t) {
h2Tag = false;
}
}
}
From another class parser runs as follows:
List<Item> list = Parser.parse();
All is good, but there is a problem. At the end of parsing in the final list "List itemList" contains 980 elements onto, instead of 1000. But in the console there is all of 1000 elements (items). That is, some threads for some reason did not call in the handleText method the addItem method.
I already tried to change the type of itemList to ArrayList, CopyOnWriteArrayList, Vector. Makes the method addItem synchronized, changed its call on the synchronized block. All this only changes the number of elements a little, but the final thousand can not be obtained.
I also tried to parse a smaller number of pages (ten). As the result the list is empty, but in the console all 10.
If I remove multi-threading, then everything works fine, but, of course, slowly. That's not good.
If decrease the number of concurrent threads, the number of items in the list is close to the desired 1000, if increase - a little distanced from 1000. That is, I think, there is a struggle for the ability to record to the list. But then why are synchronization not working?
What's the problem?
After your parse() call returns, all of your 1000 Threads have been started, but it is not guaranteed that they are finished. In fact, they aren't that's the problem you see. I would heavily recommend not write this by yourself but use the tools provided for this kind of job by the SDK.
The documentation Thread Pools and the ThreadPoolExecutor are e.g. a good starting point. Again, don't implement this yourself if you are not absolutely sure you have too, because writing such multi-threading code is pure pain.
Your code should look something like this:
ExecutorService executor = Executors.newFixedThreadPool(20);
List<Future<?>> futures = new ArrayList<Future<?>>(1000);
for (int i = 0; i < 1000; i++) {
futures.add(executor.submit(new Runnable() {...}));
}
for (Future<?> f : futures) {
f.get();
}
There is no problem with the code, it is working as you have coded. the problem is with the last iteration. rest all iterations will work properly, but during the last iteration which is from 980 to 1000, the threads are created, but the main process, does not waits for the other thread to complete, and then return the list. therefore you will be getting some odd number between 980 to 1000, if you are working with 20 threads at a time.
Now you can try adding Thread.wait(50), before returning the list, in that case your main thread will wait, some time, and may be by the time, other threads might finish the processing.
or you can use some syncronization API from java. Instead of Thread.wait(), use CountDownLatch, this will help you to wait for the threads to complete the processing, and then you can create new threads.