There are a lot of concurrent mod exception questions, but I'm unable to find an answer that has helped me resolve my issue. If you find an answer that does, please supply a link instead of just down voting.
So I originally got a concurrent mod error when attempting to search through an arraylist and remove elements. For a while, I had it resolved by creating a second arraylist, adding the discovered elements to it, then using removeAll() outside the for loop. This seemed to work, but as I used the for loop to import data from multiple files I started getting concurrent modification exceptions again, but intermittently for some reason. Any help would be greatly appreciated.
Here's the specific method having the problem (as well as the other methods it calls...):
public static void removeData(ServiceRequest r) {
readData();
ArrayList<ServiceRequest> targets = new ArrayList<ServiceRequest>();
for (ServiceRequest s : serviceQueue) {
//ConcurrentModification Exception triggered on previous line
if (
s.getClient().getSms() == r.getClient().getSms() &&
s.getTech().getName().equals(r.getTech().getName()) &&
s.getDate().equals(r.getDate())) {
JOptionPane.showMessageDialog(null, s.getClient().getSms() + "'s Service Request with " + s.getTech().getName() + " on " + s.getDate().toString() + " has been removed!");
targets.add(s);
System.out.print("targetted"); }
}
if (targets.isEmpty()) { System.out.print("*"); }
else {
System.out.print("removed");
serviceQueue.removeAll(targets);
writeData(); }
}
public static void addData(ServiceRequest r) {
readData();
removeData(r);
if (r.getClient().getStatus().equals("MEMBER") || r.getClient().getStatus().equals("ALISTER")) {
serviceQueue.add(r); }
else if (r.getClient().getStatus().equals("BANNED") || r.getClient().getStatus().equals("UNKNOWN")) {
JOptionPane.showMessageDialog(null, "New Request failed: " + r.getClient().getSms() + " is " + r.getClient().getStatus() + "!", "ERROR: " + r.getClient().getSms(), JOptionPane.WARNING_MESSAGE);
}
else {
int response = JOptionPane.showConfirmDialog(null, r.getClient().getSms() + " is " + r.getClient().getStatus() + "...", "Manually Overide?", JOptionPane.OK_CANCEL_OPTION);
if (response == JOptionPane.OK_OPTION) {
serviceQueue.add(r); }
}
writeData(); }
public static void readData() {
try {
Boolean complete = false;
FileReader reader = new FileReader(f);
ObjectInputStream in = xstream.createObjectInputStream(reader);
serviceQueue.clear();
while(complete != true) {
ServiceRequest test = (ServiceRequest)in.readObject();
if(test != null && test.getDate().isAfter(LocalDate.now().minusDays(180))) {
serviceQueue.add(test); }
else { complete = true; }
}
in.close(); }
catch (IOException | ClassNotFoundException e) { e.printStackTrace(); }
}
public static void writeData() {
if(serviceQueue.isEmpty()) { serviceQueue.add(new ServiceRequest()); }
try {
FileWriter writer = new FileWriter(f);
ObjectOutputStream out = xstream.createObjectOutputStream(writer);
for(ServiceRequest r : serviceQueue) { out.writeObject(r); }
out.writeObject(null);
out.close(); }
catch (IOException e) { e.printStackTrace(); }
}
EDIT
The changes cause the concurrent mod to trigger every time rather than intermittently, which I guess means the removal code is better but the error now triggers at it.remove();
public static void removeData(ServiceRequest r) {
readData();
for(Iterator<ServiceRequest> it = serviceQueue.iterator(); it.hasNext();) {
ServiceRequest s = it.next();
if (
s.getClient().getSms() == r.getClient().getSms() &&
s.getTech().getName().equals(r.getTech().getName()) &&
s.getDate().equals(r.getDate())) {
JOptionPane.showMessageDialog(null, s.getClient().getSms() + "'s Service Request with " + s.getTech().getName() + " on " + s.getDate().toString() + " has been removed!");
it.remove(); //Triggers here (line 195)
System.out.print("targetted"); }
}
writeData(); }
Exception in thread "AWT-EventQueue-0" java.util.ConcurrentModificatio
nException
at java.util.ArrayList$Itr.checkForComodification(ArrayList.java:901)
at java.util.ArrayList$Itr.next(ArrayList.java:851)
at data.ServiceRequest.removeData(ServiceRequest.java:195)
at data.ServiceRequest.addData(ServiceRequest.java:209) <...>
EDIT
After some more searching, I've switch the for loop to:
Iterator<ServiceRequest> it = serviceQueue.iterator();
while(it.hasNext()) {
and it's back to intermittently triggering. By that I mean the first time I attempt to import data (the removeData method is being triggered from the addData method) it triggers the concurrent mod exception, but the next try it pushes past the failure and moves on to another file. I know there's a lot of these concurrent mod questions, but I'm not finding anything that helps in my situation so links to other answers are more than welcome...
This is not how to do it, to remove elements while going through a List you use an iterator. Like that :
List<ServiceRequest> targets = new ArrayList<ServiceRequest>();
for(Iterator<ServiceRequest> it = targets.iterator(); it.hasNext();) {
ServiceRequest currentServReq = it.next();
if(someCondition) {
it.remove();
}
}
And you will not get ConcurrentModificationException this way if you only have one thread.
If there is multiple threads involved in your code, you may still get ConcurrentModificationException. One way to solve this, is to use Collections.synchronizedCollection(...) on your collection (serviceQueue) and as a result you will get a synchronized collection that will not produce ConcurrentModificationException. But, you code may become very slow.
Related
Faced this with a situation - in the main method, a child method is called, which checks the object, and an exception is thrown in this child method (one of the objects in the list NULL). But the code of the main method still continues to be executed!
Example code:
#Transactional
public boolean addCompany(List<Company> companies, List<Address> addresses) throws Exception{
checkAddress(addresses);
try{
for(int i = 0; i < companies.size(); i++){
if(findCompany(companies.get(i).getId()) == null && !isExistsCompany(companies.get(i))){
companies.get(i).setAddress(addresses.get(i));
this.em.persist(companies.get(i));
}
}
}catch(Exception e){
return false;
}
return true;
}
public void checkAddress(List<Address> addresses) throws Exception{
try{
if(addresses == null)
throw new Exception(Thread.currentThread().getStackTrace()[2].getClassName() + "." + Thread.currentThread().getStackTrace()[2].getMethodName() + "." + Thread.currentThread().getStackTrace()[1].getMethodName() + ": Invalid parameter: list is null");
for(Address a : addresses)
if(a == null)
throw new Exception(Thread.currentThread().getStackTrace()[2].getClassName() + "." + Thread.currentThread().getStackTrace()[2].getMethodName() + "." + Thread.currentThread().getStackTrace()[1].getMethodName() + ": Invalid list item: object is null");
}catch(Exception e){
e.printStackTrace();
}
}
In this regard, several questions arose:
- why the code does not stop?
- Is it now necessary, as an option, to get out of the situation by changing the type of the checkAddress method from void to boolean, and in the main method to process true/false?
- How is correctly handled on the frontend such error - do the text send exceptions to the frontend or just process the code 500 and if so, then why generate an exception on the backend - to help in the development process? How to deal with it competently?
Advise please.
Thanks in advance.
You are catching the Exception(s), when you do not rethrow a Exception the Java runtime considers it handled. If you expected program execution to stop then you need the Exception(s) to propagate to the caller. For example, in checkAddress change
} catch(Exception e) {
e.printStackTrace();
}
to something like
} catch(Exception e) {
e.printStackTrace();
throw e; // <-- re-throw the Exception
}
or simply remove the try and catch altogether, then the Exception is automatically thrown to the caller. Also, in Java 8+, you could use a Stream. Like,
public void checkAddress(List<Address> addresses) throws Exception {
if (addresses == null) {
StackTraceElement[] ste = Thread.currentThread().getStackTrace();
throw new Exception(ste[2].getClassName() + "."
+ ste[2].getMethodName() + "." + ste[1].getMethodName()
+ ": Invalid parameter: list is null");
}
if (addresses.stream().anyMatch(a -> a == null)) {
StackTraceElement[] ste = Thread.currentThread().getStackTrace();
throw new Exception(ste[2].getClassName() + "."
+ ste[2].getMethodName() + "." + ste[1].getMethodName()
+ ": Invalid list item: object is null");
}
}
You need to remove try.. catch block from inside checkAddress() method. That way, any exception thrown from inside checkAddress() are propagate to its caller.
In addCompany() method, put call to checkAddress() method inside try .. catch and handle the exception there.
When checkAddress() throws exception, code execution will jump to catch block.
e.printStackTrace();
This line suppresses the exception, causing your code to continue rather than fail. It prints the stack trace, which might make it look like the exception is being thrown, but it's not getting any further than that line.
You almost never want to use printStackTrace(), you should instead properly handle the exceptions you intend to, or just let the exception propagate to the callers of your method.
Try this:
public void checkAddress(List<Address> addresses) throws Exception{
if(addresses == null)
throw new Exception(Thread.currentThread().getStackTrace()[2].getClassName() + "." + Thread.currentThread().getStackTrace()[2].getMethodName() + "." + Thread.currentThread().getStackTrace()[1].getMethodName() + ": Invalid parameter: list is null");
for(Address a : addresses)
if(a == null)
throw new Exception(Thread.currentThread().getStackTrace()[2].getClassName() + "." + Thread.currentThread().getStackTrace()[2].getMethodName() + "." + Thread.currentThread().getStackTrace()[1].getMethodName() + ": Invalid list item: object is null");
}
}
What is all that stuff about threads? Crazy code.
Don't allow anyone to add a null instance to the List in the first place.
I might write it this way:
public void checkAddresses(List<Address> addresses) {
if (addresses == null) throw new IllegalArgumentException("Address List cannot be null");
for (Address a : addresses) {
if (a == null) throw new IllegalArgumentException("Address cannot be null");
}
}
I use dropbox /delta endpoint to track changes inside Dropbox.
More precisely, the following piece of code allow me to track changes in "/superfolder" recursively (I'm using here DbxClientV1):
List<String> listOfResults = new ArrayList<String>();
String path = "/superfolder";
String cursor = null;
while (true) {
DbxDelta<DbxEntry> deltaWithPathPrefix = client.getDeltaWithPathPrefix(cursor, path);
cursor = deltaWithPathPrefix.cursor;
if (deltaWithPathPrefix.reset) {
System.out.println("Reset!");
}
for (DbxDelta.Entry entry : deltaWithPathPrefix.entries) {
if (entry.metadata == null) {
System.out.println("Deleted: " + entry.lcPath);
listOfResults.add(entry.lcPath);
} else {
System.out.println("Added or modified: " + entry.lcPath);
}
}
if (!deltaWithPathPrefix.hasMore) {
try {
Thread.sleep(1000);
} catch (InterruptedException ex) {
Logger.getLogger(MainSearchV1.class.getName()).log(Level.SEVERE, null, ex);
}
}
}
Now, I've switched to DbxClientV2 client. To track changes on dropbox I use client.files.listFolder() in the following form:
TreeMap<String, Metadata> children = new TreeMap<String, Metadata>();
Files.ListFolderResult result;
String cursor = null;
while (true) {
if (cursor == null) {
result = client.files.listFolder("/superfolder");
} else {
result = client.files.listFolderContinue(cursor);
}
cursor = result.cursor;
for (Metadata md : result.entries) {
if (md instanceof DeletedMetadata) {
children.remove(md.pathLower);
System.out.println("Deleted: " + md.pathLower);
} else {
children.put(md.pathLower, md);
System.out.println("State: " + md.pathLower);
System.out.println(md.toString());
}
}
if (!result.hasMore) {
try {
Thread.sleep(1000);
} catch (InterruptedException ex) {
}
}
}
Regretably, I've discovered that I can only track changes only of "superfolder" folder.
Is there a way to get a "global cursor" that tracks changes recursively in Dropbox API v2?
The Java SDK uses the builder pattern for pretty much all calls with multiple optional arguments. If I understand your question correctly, I think you're looking for this:
result = client.files.listFolderBuilder("/superfolder")
.recursive(true)
.start();
EDIT: You asked about a "global" cursor. I think you actually meant recursive, but in case you really meant global, you can pass an empty string ("") as a path to represent the root.
Below is my code throwing java.util.ConcurrentModificationException, which is being executed from servlet.
The exception occurred when multiple users try to access this code, and exception is at this line:
for(Message msg : dayWiseMsgs)
Code:
List<Message> newMessages = Collections.synchronizedList(
new LinkedList<Message>());
try{
logger.debug("Last Message Id = " + lastMessageId +
" For Chat Room=" + this.getName());
List<List<Message>> allMessages = new LinkedList<List<Message>>(
getMessages().values());
for (List<Message> dayWiseMsgs : allMessages) {
for(Message msg : dayWiseMsgs){
newMessages.add(msg);
this.setLastPushMessageId(msg.getId());
}
}
}
}
allMessages=null;
} catch(Exception e){
e.printStackTrace();
}
return newMessages;
ConcurrentModificationException occurs when Collection will be changed while some thread is traversing over it using iterator, which can happen in case of multithreaded as well as single threaded environment.
Talking about your code, this situation can happen when 1 thread is creating newMessages which is synchronized :
List<Message> newMessages = Collections.synchronizedList(
new LinkedList<Message>());
while other is adding elements inside it:
newMessages.add(msg);
Moving the synchronized keyword at method level as below might work for you:
public synchronized List<Message> test() {
List<Message> newMessages = new LinkedList<Message>();
try {
logger.debug("Last Message Id = " + lastMessageId
+ " For Chat Room=" + this.getName());
List<List<Message>> allMessages = new LinkedList<List<Message>>(
getMessages().values());
for (List<Message> dayWiseMsgs : allMessages) {
if (CollectionUtils.isNotEmpty(dayWiseMsgs)
&& lastMessageId < dayWiseMsgs.get(
dayWiseMsgs.size() - 1).getId()) {
for(Message message : dayWiseMsgs){
if (message!= null && message.getId() > lastMessageId) {
newMessages.add(message);
this.setLastPushMessageId(message.getId());
}
}
}
}
allMessages = null;
} catch (Exception e) {
e.printStackTrace();
}
return newMessages;
}
Add below dependency in your classpath:
<dependency>
<groupId>commons-collections</groupId>
<artifactId>commons-collections</artifactId>
<version>3.2.1</version>
</dependency>
The ConcurrentModificationException is usually thrown when iterating through the list and in the same time usually another thread or even the same loop tries to modify (add / remove) the contents of the list.
now you have list of newMessages which you have made synchronized by calling Collections.synchronizedList
but you have not made allMessages synchronized, you are creating it using newMessages though.
i have solved it using for loop and synchronized:
what i did is: replaced foreach loop with simple for and modify the creation of list, made it synchronized :
chatRoom.getMessages().put(key, Collections.synchronizedList(new ArrayList<Message>()));
List<List<Message>> allMessages =new LinkedList<List<Message>>(getMessages().values());
for (List<Message> dayWiseMsgs : allMessages) {
//List<Message> dayMsgs = new LinkedList<Message>(dayWiseMsgs);
if (lastMessageId < dayWiseMsgs.get(dayWiseMsgs.size() - 1).getId()) {
//for (Message msg : dayWiseMsgs) {
Message msg = null;
for(int i =0 ; i < dayWiseMsgs.size() ; i++){
msg = dayWiseMsgs.get(i);
if (msg.getId() > lastMessageId ) {
newMessages.add(msg);
this.setLastPushMessageId(msg.getId());
}
}
}
}
So I am writing my own piece of stuff using jzmq GIT master branch and ZeroMQ 3.2.3.
After installation I tried to test the following simple PUB/SUB program, where a publisher and a subscriber talk in a single process. Since the test is under Windows, I used TCP.
public class ZMQReadynessTest {
private ZMQ.Context context;
#Before
public void setUp() {
context = ZMQ.context(1);
}
#Test
public void testSimpleMessage() {
String topic = "tcp://127.0.0.1:31216";
final AtomicInteger counter = new AtomicInteger();
// _____________________________________ create a simple subscriber
final ZMQ.Socket subscribeSocket = context.socket(ZMQ.SUB);
subscribeSocket.connect(topic);
subscribeSocket.subscribe("TestTopic".getBytes());
Thread subThread = new Thread() {
#Override
public void run() {
while (true) {
String value = null;
// This would result in trouble /\/\/\/\/\/\/\/\/\
{
ByteBuffer buffer = ByteBuffer.allocateDirect(100);
if (subscribeSocket.recvZeroCopy( buffer,
buffer.remaining(),
ZMQ.DONTWAIT
) > 0 ) {
buffer.flip();
value = buffer.asCharBuffer().toString();
System.out.println(buffer.asCharBuffer().toString());
}
}
// This works perfectly + + + + + + + + + + + + +
/*
{
byte[] bytes = subscribeSocket.recv(ZMQ.DONTWAIT);
if (bytes == null || bytes.length == 0) {
continue;
}
value = new String(bytes);
}
*/
if (value != null && value.length() > 0) {
counter.incrementAndGet();
System.out.println(value);
break;
}
}
}
};
subThread.start();
// _____________________________ create a simple publisher
ZMQ.Socket publishSocket = context.socket(ZMQ.PUB);
publishSocket.bind("tcp://*:31216");
try {
Thread.sleep(3000); // + wait 3 sec to make sure its ready
} catch (InterruptedException e) {
e.printStackTrace();
fail();
}
// publish a sample message
try {
publishSocket.send("TestTopic".getBytes(), ZMQ.SNDMORE);
publishSocket.send("This is test string".getBytes(), 0);
subThread.join(100);
} catch (InterruptedException e) {
e.printStackTrace();
fail();
}
assertTrue(counter.get() > 0);
System.out.println(counter.get());
}
}
Now as you can see, in the subscriber if I use a simple .recv(ZMQ.DONTWAIT) method, it works perfectly. However, if I am using the direct byte buffer I got nothing returned - and I got the following exception, seems like on program exit:
Exception in thread "Thread-0" org.zeromq.ZMQException: Resource temporarily unavailable(0xb)
at org.zeromq.ZMQ$Socket.recvZeroCopy(Native Method)
at ZMQReadynessTest$1.run(ZMQReadynessTest.java:48)
I also tried to use a simple ByteBuffer (not a direct buffer), which doesn't throw the exception above; but also return me nothing.
Does anybody know how to resolve the above?
I don't want to create byte[] objects all around, as I am doing some high performance system. If this cannot be resolved, I might simply use Unsafe instead. But I really want to work in the "supposed way".
Thanks in advance.
Alex
I'm attempting to create a chat client, I'm returning a message from the javaSpace, Then setting newMessage = true; So the client can see that there is a new message that needs to be read.
public void notify(RemoteEvent ev)
{
try
{
messageRead = false;
QueueItem qiTemplate = new QueueItem();
newMessage = (QueueItem)space.take(qiTemplate,null,Long.MAX_VALUE);
System.out.println(newMessage.getSender().getName()+ ": " + newMessage.getContent());
}
catch (Exception e)
{
e.printStackTrace();
}
}
Then for the client,
while(true)
{
try
{
boolean temp = _manager.messageRead;
//System.out.println(temp);
if(!temp)
{
QueueItem nextJob = _manager.newMessage;
String nextJobNumber = nextJob.getSender().getName();
String nextJobName = nextJob.getContent();
System.out.println(nextJob.getSender().getName()+ ": " + nextJob.getContent());
jobList.append( nextJobNumber + " : " + nextJobName + "\n" );
_manager.messageRead = true;
}
} catch ( Exception e)
{
e.printStackTrace();
}
}
That right now will ALWAYS return _messager.messageRead to be true, even though I've just set it too false. If I uncomment //System.out.println(temp); the boolean will then for some reason be updated and it will equal what its meant too.
I've never come across this error before and its extremely strange to me, So I'm hoping someone can help.
You don't seem to have synchronized accesses to your boolean flag messageRead. println happens to do that for you hence what you observe.
You could probably fix your issue by decalring the flag volatile:
private volatile boolean messageRead;
That will ensure that changes you make in one thread are visible from another thread without needing to synchronize your code.