Spawning and terminating a person in a sim game (in Java) - java

I am developing a 2D grid based sim game. Progress is good.
Been cracking out code for the last few days really well, and I've been having some issues today.
I build two rooms, set the door position, and spawn a person. The person has the 2 room types that they must visit in order to be cured (It's a remake of Theme Hospital).
I click the spawn button, Person moves onto the grid from off screen, and then when the spawn is finished, they get their first path to the first room, then second, and then back to the ending spawn point.
When I say the spawn point, I mean the point off screen / off grid, when I say the ending spawn point, I mean the point where the person is when the spawn cycle is finished, and they are fully on screen / grid.
The problem now comes, what to do with the "person" (which is an object in its own right), is finished with? Should I simple set a boolean so they are no longer "active" but data on them remains? I wasn't sure, so I tried to just remove them from the ArrayList of people objects they were being held in.
I did this by assigning a number value to each person on creation which was the same as their new position in the ArrayList, and then when removing them, using that number. I know that in itself is floored, but I'm only testing with 1 person right now. If anyone can give me some help on that, fantastic! But I suppose that is more a sub question.
When the person is to be removed, they are, and I check the size of the arraylist, and then I get the following error... "Exception in thread "AWT-EventQueue-0" java.util.ConcurrentModificationException"
I did some researching and I understand this is to do with synchronisation of objects in different threads, but I'm not sure that I have more than one thread. I do have a single timer, and I don't think the people ArrayList is accessed elsewhere.
Any Thoughts? Ideas? Suggestions? Comments on this?
Thanks in advance!
(I will soon post a video and update this question with a link to it)

Typically I give every person or entity or whatever a boolean field called isMarkedForDeletion. Then during the main loop, they will either be told to update(), or if they are marked for deletion their index will be added to a deletion list. Once you have the deletion list all populated, you can iterate through the deletion list and remove those objects from the main list. Alternatively you can just iterate backwards and pull from the tail end of the list.
This may or may not explain your ConcurrentModificationException - I've never gotten them when working with ArrayList's before. However, I've gotten them from LinkedList's and it was precisely for the reason you described and had nothing to do with threads. The actual cause was using an Iterator. The following will cause a ConcurrentModificationException:
for (Iterator i = list.iterator(); i.hasNext();)
{
Person o = i.next();
o.update();
if (list.isMarkedForDeletion())
{
list.remove(o);
}
}
This will not cause an Exception:
ArrayList deletedObjects = new ArrayList();
for (Iterator i = list.iterator(); i.hasNext();)
{
Person o = i.next();
o.update();
if (list.isMarkedForDeletion())
{
deletedObjects.add(o);
}
}
for (int i = 0; i < deletedObjects.size(); i++)
{
list.remove(deletedObjects.get(i));
}
Perhaps the simplest way to do it, will not cause an Exception:
for (int i = list.size()-1; i >= 0; i--)
{
Person o = list.get(i);
if (o.isMarkedForDeletion())
{
list.remove(i);
}
else
{
o.update();
}
}

Just a wild guess due to the lack of any code excerpts, but most probably your rendering is iterating through the ArrayList on Swing's thread, while you another thread (the timer I guess?) tries to remove the person from the list.
If that's the case, one way to go is to have Swing remove the person from the list (between two renderings) as:
// peopleArray and personInstance should be final
Runnable removePersonTask = new Runnable() {
public void run() {
peopleArray.remove(personInstance).
}
};
SwingUtilities.invokeLater(removePersonTask).

One of the more common reasons for this problem is because you can not modify an ArrayList while you are iterating over it.
Also, since you have a GUI, you have at least two threads. Swing and AWT run on a separate thread. So if the GUI is directly accessing the ArrayList, there might be some problems there.
But without code, it's not possible to tell for sure what the problem is or might be.

Related

Accurate data on a map accessed by many threads

I am trying to sort objects into five separate groups depending on a weight given to them at instantiation.
Now, I want to sort these objects into the five groups by their weights. In order to do this, each one must be compared to the other.
Now the problem I'm having is these objects are added to the groups on separate worker threads. Each one is sent to the synchronized sorting function, which compares against all members currently in the three groups, after an object has completed downloading a picture.
The groups have been set up as two different maps. The first being a Hashtable, which crashes the program throwing an unknown ConcurrencyIssue. When I use a ConcurrentHashMap, the data is wrong because it doesn't remove the entry in time before the next object is compared against the ConcurrentHashmap. So this causes a logic error and yields groups that are sorted correctly only half of the time.
I need the hashmap to immediately remove the entry from the map before the next sort occurs... I thought synchronizing the function would do this but it still doesn't seem to work.
Is there a better way to sort objects against each other that are being added to a datastructure by worker threads? Thanks! I'm a little lost on this one.
private synchronized void sortingHat(Moment moment) {
try {
ConcurrentHashMap[] helperList = {postedOverlays, chanl_2, chanl_3, chanl_4, chanl_5};
Moment moment1 = moment;
//Iterate over all channels going from highest channel to lowest
for (int i = channelCount - 1; i > 0; i--) {
ConcurrentHashMap<String, Moment> table = helperList[i];
Set<String> keys = table.keySet();
boolean mOverlap = false;
double width = getWidthbyChannel(i);
//If there is no objects in table, don't bother trying to compare...
if (!table.isEmpty()) {
//Iterate over all objects currently in the hashmap
for (String objId : keys) {
Moment moment2 = table.get(objId);
//x-Overlap
if ((moment2.x + width >= moment1.x - width) ||
(moment2.x - width <= moment1.x + width)) {
//y-Overlap
if ((moment2.y + width >= moment1.y - width) ||
(moment2.y - width <= moment1.y + width)) {
//If there is overlap, only replace the moment with the greater weight.
if (moment1.weight >= moment2.weight) {
mOverlap = true;
table.remove(objId);
table.put(moment1.id, moment1);
}
}
}
}
}
//If there is no overlap, add to channel anyway
if (!mOverlap) {
table.put(moment1.id, moment1);
}
}
} catch (Exception e) {
Log.d("SortingHat", e.toString());
}
}
The table.remove(objId) is where the problems occur. Moment A gets sent to sorting function, and has no problems. Moment B is added, it overlaps, it compares against Moment A. If Moment B is less weight than Moment A, everything is fine. If Moment B is weighted more and A has to be removed, then when moment C gets sorted moment A will still be in the hashmap along with moment B. And so that seems to be where the logic error is.
You are having an issue with your synchronization.
The synchronize you use, will synchronize using the "this" lock. You can imagine it like this:
public synchronized void foo() { ... }
is the same as
public void foo() {
synchronized(this) {
....
}
}
This means, before entering, the current Thread will try to acquire "this object" as a lock. Now, if you have a worker Thread, that also has a synchronized method (for adding stuff to the table), they won't totally exclude each other. What you wanted is, that one Thread has to finish with his work, before the next one can start its work.
The first being a Hashtable, which crashes the program throwing an unknown ConcurrencyIssue.
This problem accourse because it may happen, that 2 Threads call something at the same time. To illustrate, imagine one Thread calling put(key, value) on it and another Thread calling remove(key). If those calls get executed at the same time (like by different cores) what will be the resulting HashTable? Because noone can say for sure, a ConcurrentModificationException will be thrown. Note: This is a verry simplyfied explanation!
When I use a ConcurrentHashMap, the data is wrong because it doesn't remove the entry in time before the next object is compared against the ConcurrentHashmap
The ConcurrentHashMap is a utility, for avoiding said concurrency issues, it is not magical, multi functional, unicorn hunting, butter knife. It snynchronizes the mehtod calls, which results in the fact, that only one Thread can either add to or remove from or do any other work on the HashMap. It does not have the same functionallity as a Lock of some sort, which would result in the access over the map being allocated to on Thread.
There could be one Thread that wants to call add and one that want to call remove. The ConcurrentHashMap only limits those calls in the matter, that they can't happen at the same time. Which comes first? You have power over that (in this scenario). What you want is, that one thread has to finish with his work, before the next one can do its work.
What you realy need is up to you. The java.util.concurrent package brings a whole arsenal of classes you could use. For example:
You could use a lock for each Map. With that, each Thread (either sorting/removing/adding or whatever) could first fetch the Lock for said Map and than work on that Map, like this:
public Worker implements Runnable {
private int idOfMap = ...;
#Override
public void run() {
Lock lock = getLock(idOfMap);
try {
lock.lock();
// The work goes here
//...
} finally {
lock.unlock();
}
}
}
The line lock.lock() would ensure, that there is no other Thread, that is currently working on the Map and modifing it, after the method call returns and this Thread will therefore have the mutial access over the Map. No one sort, before you are finished removing the right element.
Of course, you would somehow have to hold said locks, like in a data-object. With that being said, you could also utilize the Semaphore, synchronized(map) in each Thread or formulating your work on the Map in the form of Runnables and passing those to another Thread that calls all Runnables he received one by one. The possibilities are nearly endless. I personally would recommend on starting with the lock.

pojo declaraion outside forloop

I have an one scenario in my application,
I have to add 20 POJO objects into ArrayList. In that case I have a method like below.
public void methodname() {
ArrayList arr = new ArrayList();
for(int i=0;i<20;i++) {
User userobj = new User();
userobj.setName("xxx");
userobj.setFirstName("xxx");
userobj.setLastName("yyy");
arr.add(userobj);
} // end of for loop
}
one of friends suggest to change the UserObj declaration outside for loop.
public void methodname() {
User userobj = new User();
ArrayList arr = new ArrayList();
for(int i=0;i<20;i++) {
userobj.setName("xxx");
userobj.setFirstName("xxx");
userobj.setLastName("yyy");
arr.add(userobj);
} // end of for loop
}
in the first approach, I created the userobj inside the for loop, so when next iteration comes previous userobj will be eligible for garbage collector..
I would like to know is there any significant performance will improve on the second approach?
I would like to know is there any significant performance will improve on the second approach?
Did you experience a difference?
When programming you should focus on correctness and readability of your code.
Do not even Think about performance unless you have an actual performance problem and you have proven by profiling that a certain construct is the cause.
The ultimate universal performance tip is:
The fastest way to do something is not doing it.
So focus on good algorithms that avoid unneeded/hidden loops rather than on syntax variants that may improve performance.
The main difference between the first and the second approach is that in the first case you create 20 different User in memory which are assigned to the array.
In the second case you create only one User in memory but change its properties 20 times and assign the same User to all 20 positions of the array.
Regardless of the first scenario or the second, your User instances created are eligible for garbage collection only when the array itself is eligible for garbage collection, expect you remove the association with the array.
Garbage collection takes place only for an instance if there is no other instance referencing it.
Both the ways, will produce different results.
In the First one, you create 20 separate Objects, and add them to the List. Thus, changes on one of them, won't affect the others.
The Second, however, has the same object. Thus, changes on one will reflect the others. Actually, at the end, the attributes of the all the Objects would be the same, i.e, equal to the last added Object
Performance-wise, you can't say. The Objects would only be eligible for garbage collection, when there are no references pointing to them. However, as both the ways perform separate functions, you can't compare them.
Alas, your Friend is wrong. The First way is what you're looking for.
It needs to be inside the loop, otherwise you are only adding the SAME user 20 times !
On the second approach you will have only one last object in the list
I think that the right way is:
- declaration outside
- instantiation inside
public void methodname() {
ArrayList arr = new ArrayList();
User userobj;
for(int i=0;i<20;i++) {
userobj = new User();
userobj.setName("xxx");
userobj.setFirstName("xxx");
userobj.setLastName("yyy");
arr.add(userobj);
} // end of for loop
}

Java ConcurrentModificationException problems with classes

I am essentially doing the following:
Creating an object (for example a weapon object), that automatically adds that object to a list off all of those types of objects (ArrayList<Weapons>).
JPanel paints every 10 seconds with an updater thread that iterates through the ArrayList<Weapons>. I am also sending 'questions' to a server on another machine, i.e. asking if that weapon is allowed. If it is not, the weapon object is modified by the client computer. However, whenever I modify it, I receive a ConcurrentModificationException. Instead of crashing, which I actually hope it would do at this point, since the method that changes the weapon object is on a different thread, the whole program just locks up.
I have more than 1000 lines of code in this program, and more than three threads running that access the list, so if you need any code please ask but I'd rather not post right now because in my mind this seems like a trivial question for an expert at threads.
Thanks!
(Object is made >> added to list of objects >> JPanel's "Updater" thread is constantly painting all objects every 10 ticks...
Server says that object isn't allowed >> A thread on the client computer removes that object (or toggles a boolean that says it is not visible) >> ConcurrentModificationException).
Quoting the Javadoc of ArrayList
Note that this implementation is not synchronized. If multiple threads access an ArrayList instance concurrently, and at least one of the threads modifies the list structurally, it must be synchronized externally.
You describe multiple threads accessing the list, and at least one of them modifying it. So, all accesses to the list must be done in mutually synchronized blocks.
e.g. to iterate the list:
synchronized (list) {
for (Weapons weapons : list) {
// ...
}
}
e.g. to remove an item from the list:
synchronized (list) {
list.remove(0);
}
I think you can use a synchronised version of collection or list, i.e. java.util.Collections.synchronizedCollection(Collection<>), java.util.Collections.synchronizedList(List<>). Also, if you iterate over the list and remove items, ensure that use an implementation that enable remove item from the iterator. A good candidate is java.util.ArrayList.
Other technique is use "monitors", you can declare an attribute like: private static Object monitor = new Object(); then when the code tries to access to the list, protect the code inside a synchronized(monitor) block. Using this technique you ensure that no other thread will be able to modify your list until no protected code is running.
Please, excuse my English :).

multiple threads accessing an ArrayList

i have an ArrayList that's used to buffer data so that other threads can read them
this array constantly has data added to it since it's reading from a udp source, and the other threads constantly reading from that array.Then the data is removed from the array.
this is not the actual code but a simplified example :
public class PacketReader implements Runnable{
pubic static ArrayList<Packet> buffer = new ArrayList() ;
#Override
public void run(){
while(bActive){
//read from udp source and add data to the array
}
}
public class Player implements Runnable(){
#Override
public void run(){
//read packet from buffer
//decode packets
// now for the problem :
PacketReader.buffer.remove(the packet that's been read);
}
}
The remove() method removes packets from the array and then shifts all the packets on the right to the left to cover the void.
My concern is : since the buffer is constantly being added to and read from by multiple threads , would the remove() method make issues since its gonna have to shift packets to the left?
i mean if .add() or .get() methods get called on that arraylist at the same time that shift is being done would it be a problem ?
i do get index out of bounds exception sometimes and its something like :
index : 100 size 300 , which is strange cuz index is within size , so i want to know if this is what may possibly be causing the problem or should i look for other problems .
thank you
It sounds like what you really want is a BlockingQueue. ArrayBlockingQueue is probably a good choice. If you need an unbounded queue and don't care about extra memory utilization (relative to ArrayBlockingQueue), LinkedBlockingQueue also works.
It lets you push items in and pop them out, in a thread-safe and efficient way. The behavior of those pushes and pops can differ (what happens when you try to push to a full queue, or pop from an empty one?), and the JavaDocs for the BlockingQueue interface have a table that shows all of these behaviors nicely.
A thread-safe List (regardless of whether it comes from synchronizedList or CopyOnWriteArrayList) isn't actually enough, because your use case uses a classic check-then-act pattern, and that's inherently racy. Consider this snippet:
if(!list.isEmpty()) {
Packet p = list.remove(0); // remove the first item
process(p);
}
Even if list is thread-safe, this usage is not! What if list has one element during the "if" check, but then another thread removes it before you get to remove(0)?
You can get around this by synchronizing around both actions:
Pattern p;
synchronized (list) {
if (list.isEmpty()) {
p = null;
} else {
p = list.remove(0);
}
}
if (p != null) {
process(p); // we don't want to call process(..) while still synchronized!
}
This is less efficient and takes more code than a BlockingQueue, though, so there's no reason to do it.
Yes there would be problems because ArrayList is not thread-safe, the internal state of the ArrayList object would be corrupted and eventually you would have some incorrect output or runtime exceptions appearing. You can try using synchronizedList(List list), or if it's a good fit you could try using a CopyOnWriteArrayList.
This issue is the Producer–consumer problem. You can see how much people fix it by using a lock of some kind taking turns extracting an object out of a buffer (a List in your case). There are thread safe buffer implementations you could look at as well if you don't necessarily need a List.

another ConcurrentModificationException

I am new to Java and especially to iterating through lists and modifying it's elements. I went through dozens of similar questions, but after many tries nothing worked.
In the following code sample an exceptions is thrown. It is not related to concurrent thread as I only have one thread. Netbeans output sais that the exception occurs in line 5(CustomerData customer = i.next();) :
CustomerData tempCustomer = new CustomerData("",tagID,0);
tempCustomer.setName(name);
tempCustomer.setSize(size);
for(ListIterator<CustomerData> i = customers.listIterator(); i.hasNext(); )
{
CustomerData customer = i.next();
if(customer.getTagID().contains(tagID))
{
Object[] options = {"overwrite", "do not overwrite"};
int n = JOptionPane.showOptionDialog(rootPane,
"TagID already exists. overwrite?",
"?",
JOptionPane.YES_NO_OPTION,
JOptionPane.QUESTION_MESSAGE,
null,
options,
rootPane);
if ( n == JOptionPane.YES_OPTION ){
i.set(tempCustomer);
}
}
else{
addCustomer();
}
}
The whole code is only supposed to check if the element has matching tagID and if it does, replace two values (name and size) in it. Initially I tried to use setName() and setSize() inside the for loop on the element, but after it didn't work and after reading other related questions, I assigned the values to temporary object before the loop and the used the iterator's set method to replace current element. But still no success and it even seems it never gets that far because the exception comes after line 5...
The problem is presumably that this line:
addCustomer();
is trying to modify customers while you're in the middle of iterating over it. This isn't allowed.
And anyway, it seems like a logic error: presumably you want to call addCustomer only once, after the loop, if no customer had the right tagID, but your current code tries to call addCustomer for each customer with with the wrong tagID. So you need to use a boolean variable during the loop to keep track of whether any customer matched, and then, after the loop, call addCustomer if appropriate.
ConcurentModificationException does not always indicate that an object has been concurrently modified by a different thread.
In your case the problem might be in following (guessing by addCustomer method): you are getting iterator of collection and then modifiying this collection. Because collection is modified, iterator becomes invalid and exception is thrown.
My suggestion will be create temproray list of customers which will you will append to your original customer list, when your iteration finished.
As mentioned in javadocs:
if a thread modifies a collection directly while it is iterating over
the collection with a fail-fast iterator, the iterator will throw this
exception.
I guess it is occurring after a call to addCustomer() which modifies the customers object. You can either hold the newly added objects in a different collection until end of the loop or break out of the loop and restart after adding.

Categories