Java Set gets full - java

I am making a particle emitter.
Every "Rendered" object is stored in a HashSet, and when there's lots of particles on the screen, the console spits out concurrent modification exceptions. I usually have a short lifetime on these particles so they get deleted after several seconds, but I am sure this could potentially be a problem in the future. How can I fix this?
EDIT: Code:
public class UpdatedManager {
private static Set<Updated> updates = new HashSet<>();
private UpdatedManager() {}
public static Set<Updated> getUpdates() {
return new HashSet<Updated>(updates);
}
public static boolean registerUpdated(Updated u) {
return updates.add(u);
}
public static boolean unregisterUpdated(Updated u) {
return updates.remove(u);
}
public static void update() {
for (Updated up : new HashSet<Updated>(updates))
up.update();
}
public static Set<GameObject> getGameObjects() {
Set<GameObject> objs = new HashSet<>();
for (Updated up : new HashSet<Updated>(updates)) {
if (up instanceof GameObject)
objs.add((GameObject) up);
}
return objs;
}
public static Set<GameObject> getGameObjectsByName(String name) {
Set<GameObject> objs = new HashSet<>();
for (GameObject go : new HashSet<GameObject>(getGameObjects())) {
if (go.getName() != null && go.getName().equals(name))
objs.add(go);
}
return objs;
}
public static Set<Particle> getParticles() {
Set<Particle> parts = new HashSet<>();
for (Updated up : new HashSet<Updated>(updates)) {
if (up instanceof Particle)
parts.add((Particle) up);
}
return parts;
}
}

A ConcurrentModificationException means you modified the set while iterating over it. It does not mean the set is full.
For example, the following code will throw a ConcurrentModificationException:
Set<String> set = new HashSet<>();
set.add("Hello");
for(String s : set)
set.add(s+" world");
Note that you are not guaranteed to get a ConcurrentModificationException, so you should avoid catching it. You should instead fix your code so that it doesn't cause the problem.

What makes you think that the set is full?
Concurrent modification exceptions mean that the set is being accessed by different threads in an unsafe manner.
Try a synchronised set using the Collections utilities
HashSet hashSet = new HashSet();
Set set = Collections.synchronizedSet(hashSet);
or use the synchronized keyword for the method accessing the set.

Related

Validating elements of an ArrayList to match a parameter (Java)

I need a method that checks that at least 1 element of a list matches a parameter. I've figured it out, but this code is poor and slow.
private static void validateAdvertisements(List<Advertisement> advertisements) {
List<Advertisement> inactiveAdvertisements = new ArrayList<>();
for (Advertisement advertisement : advertisements)
if (!advertisement.isActive()) inactiveAdvertisements.add(advertisement);
if (inactiveAdvertisements.size() == advertisements.size()) throw new NoAdvertisementAvailableException();
}
Is there a getter way to do this?
Make your logic short-circuit.
Since you need to throw an exception only if there are no active Advertisement instances in the list, when the first active element is encountered - break out from the loop.
private static void validateAdvertisements(List<Advertisement> advertisements) {
boolean isActiveNotFound = true;
for (Advertisement advertisement : advertisements) {
if (advertisement.isActive()) isActiveNotFound = false;
break;
}
if (isActiveNotFound) throw new NoAdvertisementAvailableException();
}
A stream-based solution using Stream.noneMatch(), this operation is short-circuit and exception would be thrown only if there are no active objects.
private static void validateAdvertisements(List<Advertisement> advertisements) {
boolean isActiveNotFound = advertisements.stream()
.noneMatch(Advertisement::isActive);
if (isActiveNotFound) throw new NoAdvertisementAvailableException();
}
In case if NoAdvertisementAvailableException is a runtime exception, it can be propagated outside the functions implementing standard functional interfaces from the JDK, like Runnable.
Here's an example that makes use of the combination Stream.findFirst() + Optional.ifPresentOrElse():
private static void validateAdvertisements(List<Advertisement> advertisements) {
advertisements.stream()
.filter(Advertisement::isActive)
.findFirst()
.ifPresentOrElse(s -> {},
() -> { throw new NoAdvertisementAvailableException(); }
);
}
Came up with the solution using Streams
private static void validateAdvertisements(List<Advertisement> advertisements) {
if (advertisements.stream().noneMatch(Advertisement::isActive)) throw new NoVideoAvailableException();
}

Why does static hashmap created for every instances?

I have a course class having one Hashmap. I'm trying to add values to the map with different objects. Map is common for all the objects so I marked it as Static still it shows weird behavior.
I have the following code -
class Course
{
static HashMap<Integer,List<String>> map;
Course()
{
map = new HashMap<>();
}
public boolean add(int id,String Course)
{
if(!map.containsKey(id))
{
map.put(id,new ArrayList<>());
}
try
{
List<String> temp = map.get(id);
temp.add(Course);
return true;
} catch (Exception e)
{
return false;
}
}
public void get()
{
System.out.println(map);
}
public static void main(String[] args)
{
Course c = new Course();
c.add(1, "abs");
c.add(2,"xyx");
c.add(1,"new");
c.add(3,"tye");
c.get();
Course c2 = new Course();
c2.add(1,"GP");
c2.add(2, "PT");
c2.get();
}
}
I have defined Hashmap as static because it is common for all the objects. But still, the new Hashmap is created for every instance.
Output
{1=[abs, new], 2=[xyx], 3=[tye]}
{1=[GP], 2=[PT]}
Because you initialize it in the constructor.
Don't. Just initialize it on the field:
static HashMap<Integer,List<String>> map = new HashMap<>();
(And remove the constructor).
And consider making the field final if you never intend to reassign it. This ensures that 1) you don't actually reassign it; 2) you actually do assign it once.

Possibility of Race Condition on using Java Locks

I've written a Java class and someone has reviewed the code and insisted that there could be a race condition in method calculate. Here's a simplified version of the class code:
public class MyClass {
private List<Integer> list;
private final ReadWriteLock lock;
public MyClass() {
list = new ArrayList<>();
lock = new ReentrantReadWriteLock();
}
public void add(Integer integer) {
lock.writeLock().lock();
try {
list.add(integer);
} finally {
lock.writeLock().unlock();
}
}
public void deleteAll() {
lock.writeLock().lock();
try {
list.clear();
} finally {
lock.writeLock().unlock();
}
}
public Integer calculate() {
List<Integer> newList = new ArrayList<>();
Integer result = 0;
lock.readLock().lock();
try {
list.forEach(integer -> {
// calculation logic that reads values from 'list' and adds only a subset of elements from 'list' in 'newList'
});
} finally {
lock.readLock().unlock();
}
setList(newList);
return result;
}
private void setList(List<Integer> newList) {
lock.writeLock().lock();
try {
list = newList;
} finally {
lock.writeLock().unlock();
}
}
}
Now my question is:
Can a race condition really happen in this method, and if so how can I solve it (either using locks or using any other method to make the class thread safe)?
Any advice would be appreciated.
There is a time gap between creation of newList and call to setList(newList). We may assume this time gap is arbitrary long, and everything can happen when it lasts, e.g. another thread adds an object which must be retained, but it will be lost when call to setList(newList) removes list with that new object.
In fact, the method calculate is modifying and should do all the work under write lock.
To clarify the above ... the statement
List<Integer> newList = new ArrayList<>();
... instantiates a data-structure (list ...) that will subsequently be used within the block of code that is intended to be protected by lock.readLock().lock();, but is not contained within it. Therefore it is not protected.
To remedy the problem, the declaration of newList should not include initialization. Nothing which affects the presumed value of this variable should exist outside of the lock-protected block.

Changes in Java 6 synchronization?

I am looking at some code that is causing an issue (Deadlock) in Java 6 and above, but not in Java 1.5.
BMP Bean:
private MyClass m_c;
public String ejbCreate(String id) throws CreateException, MyException
{
try
{
m_c = Singleton.getInstance().getObj(id);
}
catch (MyException e)
{
synchronized (Singleton.getInstance())
{
//check again
if (!Singleton.getInstance().hasObj(id)) {
m_c = new MyClass(id);
Singleton.getInstance().addObj(id, m_c);
}
else {
m_c = Singleton.getInstance().getObj(id);
}
}
}
}
Singleton:
private Map objCache = new HashMap();
private static Singleton INSTANCE = new Singleton();
public static Singleton getInstance() {
return INSTANCE;
}
public void addObj(String id, MyClass o)
{
if (this.objCache.containsKey(id)) {
this.objCache.remove(id);
}
this.objCache.put(id, o);
}
public MyClass getObj(String id) throws Exception
{
MyClass o = null;
o = (MyClass)this.objCache.get(id);
if (o == null) {
throw new MyException("Obj " +id+ " not found in cache");
}
return o;
}
public boolean hasObj(String id)
{
return this.objCache.containsKey(id);
}
The empirical evidence so far shows that putting synchronization round the whole try/catch resolves the deadlock when using Java 6.
Clearly there can be one or more threads calling
Singleton.getInstance().getObj(id)
without obtaining the lock whilst another thread has the lock and is executing the code in the synchronized block, but even after considering memory synchronization detailed in JSR-133, it doesn't look like there should be any issues in this scenario.
I am aware that I haven't explained what the issue is apart from saying it is a deadlock and that it is not ideal to paint only a prat of the picture but to paint the whole picture would take a very big canvas.
I have looked at the notes for Java 6 release and the only area that sounds relevant is around uncontended synchronization, but I do not know if that is significant in this case.
Thank you for any help.
I suspect you are not getting a deadlock (holding two locks in two different threads obtained in a different order), but rather going into an infinite loop. This can happen with HashMap if you are accessing it in a manner which is not thread safe. What happens in the linked list used to handle collisions appears to go back on itself and the reader runs forever. This has always been an issue, though some subtle difference in Java 6 could show up this problem when a different version might not.
I suggest you fix this class so it uses a thread safe collection and not retry on Exception because there is not guarantee this will happen.
There is a lot you could do to improve this class but what you really need is ConcurrentMap.computeIfAbsent added in Java 8.
Note: there is no reason to
check a key exists before attempting to remove it.
remove a key just before attempting to put it.
throw an Exception instead of returning null.
returning null when you can pass it a factory. (as per computeIfAbsent)
use a factory when the type is known in advance.
I suggest you
use a ConcurrentMap for thread safe concurrent access.
use an enum for a Singleton.
Both of these were added in Java 5.0.
public enum MyClassCache {
INSTANCE;
private final Map<String, MyClass> cache = new ConcurrentHashMap<>();
public boolean hasId(String id) {
return cache.containsKey(id);
}
public MyClass get(String id) throws IllegalStateException {
MyClass ret = cache.get(id);
if (ret == null) throw new IllegalStateException(id);
return ret;
}
public MyClass getOrCreate(String id) throws IllegalStateException {
MyClass ret = cache.get(id);
if (ret == null) {
synchronized (cache) {
ret = cache.get(id);
if (ret == null) {
cache.put(id, ret = new MyClass(id));
}
}
}
return ret;
}
}
In Java 8 you can use computeIfAbsent
public MyClass getOrCreate(String id) {
return cache.computeIfAbsent(id, MyClass::new);
}
Am I right that the core of this question is the difference between:
public void ejbCreate1(String id) throws Exception {
try {
m_c = Singleton.getInstance().getObj(id);
} catch (Exception e) {
synchronized (Singleton.getInstance()) {
//check again
if (!Singleton.getInstance().hasObj(id)) {
m_c = new MyClass(id);
Singleton.getInstance().addObj(id, m_c);
} else {
m_c = Singleton.getInstance().getObj(id);
}
}
}
}
and
public void ejbCreate2(String id) throws Exception {
synchronized (Singleton.getInstance()) {
try {
m_c = Singleton.getInstance().getObj(id);
} catch (Exception e) {
//check again
if (!Singleton.getInstance().hasObj(id)) {
m_c = new MyClass(id);
Singleton.getInstance().addObj(id, m_c);
} else {
m_c = Singleton.getInstance().getObj(id);
}
}
}
}
in Java-6 that can cause the first to hang and the second to work fine.
Clearly the primary difference is that getObj might be called by two different threads at the same time, and may even be called while another threads is creating the new object.
From Is it safe to get values from a java.util.HashMap from multiple threads (no modification)? it is likely that you are not in that situation. Conclusion is that one thread is readng from the Map (perhaps o = (MyClass) this.objCache.get(id);) while another is writing to the map by calling addObj. This is clearly a recipe for the read to crash and burn.
See Is a HashMap thread-safe for different keys? for details about the potential sinkholes.

HashMap for enum as key

I had posted somewhat similar question before also. I got clarification for my doubts as well. But still I need something more. The Hashmap will be initialized with the enum object as the key and a threadpool instance as the value. I am confused as of how to initialize the HashMap for every object been called by some other process ..To make clear :
My program, MyThreadpoolExcecutorPgm.java initializes a HashMap
My Progran AdditionHandler.java requests a thread from the HashMap by passing ThreadpoolName (enum). I am getting "No thread available from HashMap" message. Please do help me.
Below given is my code:
public class MyThreadpoolExcecutorPgm {
enum ThreadpoolName {
DR, BR, SV, MISCELLENEOUS;
}
private static String threadName;
private static HashMap<ThreadpoolName, ThreadPoolExecutor>
threadpoolExecutorHash;
public MyThreadpoolExcecutorPgm(String p_threadName) {
threadName = p_threadName;
}
public static void fillthreadpoolExecutorHash() {
int poolsize = 3;
int maxpoolsize = 3;
long keepAliveTime = 10;
ThreadPoolExecutor tp = null;
threadpoolExecutorHash = new HashMap<ThreadpoolName, ThreadPoolExecutor>();
for (ThreadpoolName poolName : ThreadpoolName.) // failing to implement
{
tp = new ThreadPoolExecutor(poolsize, maxpoolsize, keepAliveTime,
TimeUnit.SECONDS, new ArrayBlockingQueue<Runnable>(5));
threadpoolExecutorHash.put(poolName, tp);
}
}
public static ThreadPoolExecutor getThreadpoolExcecutor(
ThreadpoolName poolName) {
ThreadPoolExecutor thread = null;
if (threadpoolExecutorHash != null && poolName != null) {
thread = threadpoolExecutorHash.get(poolName);
} else {
System.out.println("No thread available from HashMap");
}
return thread;
}
}
AdditionHandler.java
public class AdditionHandler{
public void handle() {
AddProcess setObj = new AddProcess(5, 20);
ThreadPoolExecutor tpe = null;
ThreadpoolName poolName =ThreadpoolName.DR; //i am using my enum
tpe = MyThreadpoolExcecutorPgm.getThreadpoolExcecutor(poolName);
tpe.execute(setObj);
}
public static void main(String[] args) {
AdditionHandler obj = new AdditionHandler();
obj.handle();
}
}
I suspect you're just looking for the static values() method which is added to every enum:
for (ThreadpoolName poolName : ThreadpoolName.getValues())
Alternatively, you can use EnumSet.allOf():
for (ThreadpoolName poolName : EnumSet.allOf(ThreadpoolName.class))
(As Bozho says, EnumMap is a good alternative here. You still need to loop through the enum values.)
First, you'd better use EnumMap. Then make sure you have filled the map before you invoked the method.
You can iterate through enum values by one of (in descending order of preference)
for(Enum value : Enum.values())
for(Enum value : EnumSet.allOf(Enum.class))
for(Enum value : Enum.class.getEnumConstants())
But you should also be using an EnumMap.

Categories

Resources