Hi i have a race condition in given method i have 2 instances in kubernates and checking in redis
public void method(GuestDTO guestDTO) {
String executeName = "addingGuestToCache" + guestDTO.getUser();
if (!redisService.checkExecute(executeName)) {
redisService.startExecute(executeName);
OpenGuestDTO openGuestDTO = new OpenGuestDTO();
RMap<String, List<OpenGuestDTO>> openGuestDTOList = redisService.getOpenGuestDTOList();
List<OpenGuestDTO> userGuestList = openGuestDTOList.get(guestDTO.getUser());
if (userGuestList == null) {
userGuestList = Collections.synchronizedList(new ArrayList<OpenGuestDTO>());
}
for (OpenGuestDTO guestDTO1 : userGuestList) {
if (guestDTO1.getGuestName().equalsIgnoreCase(guestDTO.getGuestName())) {
redisService.deleteExecute(executeName);
return;
}
}
openGuestDTOList.add(openGuestDTO);
openGuestDTOList.fastPut(guestDTO.getUser(), userGuestList);
redisService.deleteExecute(executeName);
}else{
method(guestDTO);
}
}
Related
ExtractSourceQueryOB is an object that represents queries, a query could have a master query and in this case the master query should not be removed from the list, querySet contains strings of keys that represent queries that are required in this operation but it doesnt take account of the possibility of that query having a master. So i tried to loop through all queries checking that query has a master and in that case add that object (ExtractSourceQueryOB ) to the final list.
private List<ExtractSourceQueryOB> checkRequiredQueries(List<ExtractSourceQueryOB> extractSourceQueryList, ExtractElement extractElement) {
Set<ExtractSourceQueryOB> queryList = new HashSet();
Set<String> querySet = new HashSet();
fillUsedSymbolList(querySet, extractElement);
for(ExtractSourceQueryOB extractSourceQuery : extractSourceQueryList) {
if(extractSourceQuery.getMaster() != null ) {
for(ExtractSourceQueryOB extractSourceQuery2 : extractSourceQueryList) {
if(extractSourceQuery.getMaster().equals(extractSourceQuery2.getSymbol())){
queryList.add(extractSourceQuery2);
}
}
}
}
for (ExtractSourceQueryOB extractSourceQuery : extractSourceQueryList) {
for (String s : querySet) {
if (extractSourceQuery.getSymbol().equalsIgnoreCase(s)) {
queryList.add(extractSourceQuery);
}
}
}
return new ArrayList<>(queryList);
}
How can i simplify this method ?
You could eliminate the second for by combining that code with the first. Like,
for(ExtractSourceQueryOB extractSourceQuery : extractSourceQueryList) {
if(extractSourceQuery.getMaster() != null ) {
for(ExtractSourceQueryOB extractSourceQuery2 : extractSourceQueryList) {
if(extractSourceQuery.getMaster().equals(extractSourceQuery2.getSymbol())){
queryList.add(extractSourceQuery2);
}
}
}
for (String s : querySet) {
if (extractSourceQuery.getSymbol().equalsIgnoreCase(s)) {
queryList.add(extractSourceQuery);
}
}
}
private List<ExtractSourceQueryOB> checkRequiredQueries(List<ExtractSourceQueryOB> extractSourceQueryList, ExtractElement extractElement) {
Set<ExtractSourceQueryOB> queryList = new HashSet();
Set<String> querySet = new HashSet();
fillUsedSymbolList(querySet, extractElement);
for (ExtractSourceQueryOB extractSourceQuery : extractSourceQueryList) {
if (isyUsedAsMaster(extractSourceQuery,extractSourceQueryList) || isUsed(extractSourceQuery,querySet, extractSourceQueryList)) {
queryList.add(extractSourceQuery);
}
}
return new ArrayList<>(queryList);
}
private boolean isyUsedAsMaster(ExtractSourceQueryOB extractSourceQuery, List<ExtractSourceQueryOB> extractSourceQueryList) {
if (extractSourceQuery.getMaster() != null) {
for (ExtractSourceQueryOB extractSourceQuery2 : extractSourceQueryList) {
if (extractSourceQuery.getMaster().equals(extractSourceQuery2.getSymbol())) {
return true;
}
}
}
return false;
}
private boolean isUsed(ExtractSourceQueryOB extractSourceQuery, Set<String> querySet, List<ExtractSourceQueryOB> extractSourceQueryList) {
for (String s : querySet) {
if(extractSourceQuery.getSymbol().equalsIgnoreCase(s)) {
return true;
}
}
return false;
}
Previous answer above is correct but this is with some refactoring
I'm telling you that I was able to get the highs with and without inheritance automated, but now I have the same problem to edit, it happens
I want to first edit the methods of the superclass and then the superclass
But I do not succeed:
ParamBuilder.java
private LinkedList<Object>loadMethods(IPersistente ip) throws Exception{
LinkedList<Method> m = new LinkedList();
Child s = ip.getClass().getAnnotation(Child.class);
Method[] me = null;
if(s != null && ip.getId() == 0){
me = ip.getClass().getSuperclass().getDeclaredMethods();
} else {
// only this if is left so that the modifications with inheritances are automated, xq with the highs I could
if(s != null){
me = ip.getClass().getSuperclass().getDeclaredMethods();
} else {
me = ip.getClass().getDeclaredMethods();
}
}
for(Method campo : me){
if (campo.getName().startsWith("get") && !campo.getName().startsWith("getClass")) {
Method metodo = campo;
if(metodo.getParameterCount() == 0) {
if(metodo.isAnnotationPresent(Sort.class)){
m.add(metodo);
}
}
}
}
if(ip instanceof IDependiente && !ip.check()){
Collections.sort(m, new SortDesc());
} else {
Collections.sort(m, new SortAsc());
}
return load(ip, m);
}
I await your responses and greetings.
I Have a multithreaded environment in android app. I use a singleton class to store data. This singleton class contains a arraylist that is accessed using a synchronized method.
The app uses this arraylist to render images in app.
Initial problem : Concurrent modification error use to come so I made the get arraylist function syncronized.
Current Problem:Concurrent modification error not coming but in between empty arraylist returned (maybe when there is concurrent access).
Objective : I want to detect when Concurrent modification so that Instead of empty arraylist being return I can return last state of the arraylist.
public synchronized List<FrameData> getCurrentDataToShow() {
List<FrameData> lisCurrDataToShow = new ArrayList<FrameData>();
//for (FrameData fd : listFrameData) {//concurrent modification exception
//todo iterator test
Iterator<FrameData> iterator = listFrameData.iterator();
while (iterator.hasNext()) {
FrameData fd = iterator.next();
long currentTimeInMillis = java.lang.System.currentTimeMillis();
if ((currentTimeInMillis > fd.getStartDate().getTime() && currentTimeInMillis < fd.getEndDate().getTime()) || (fd.isAllDay() && DateUtils.isToday(fd.getStartDate().getTime()))) {
if (new File(ImageFrameActivity.ROOT_FOLDER_FILES + fd.getFileName()).exists()) {
lisCurrDataToShow.add(fd);
}
}
}
if (lisCurrDataToShow.size() == 0) {
lisCurrDataToShow.add(new FrameData(defaultFileName, null, null, null, String.valueOf(120), false));
}
return lisCurrDataToShow;
}
Referred to Detecting concurrent modifications?
Please help!
EDIT1:
This problem occurs rarely not everytime.
If a threads is accessing getCurrentDataToShow() and another thread tries to access this function what will the function return?? I'm new to multithreading , please guide
Edit 2
in oncreate following methods of singleton are called periodically
DataModelManager.getInstance().getCurrentDataToShow();
DataModelManager.getInstance().parseData(responseString);
Complete singleton class
public class DataModelManager {
private static DataModelManager dataModelManager;
private ImageFrameActivity imageFrameAct;
private String defaultFileName;
public List<FrameData> listFrameData = new ArrayList<FrameData>();
// public CopyOnWriteArrayList<FrameData> listFrameData= new CopyOnWriteArrayList<FrameData>();
private String screensaverName;
private boolean isToDownloadDeafultFiles;
private String tickerMsg = null;
private boolean showTicker = false;
private boolean showHotspot = false;
private String hotspotFileName=null;
public String getDefaultFileName() {
return defaultFileName;
}
public boolean isToDownloadDeafultFiles() {
return isToDownloadDeafultFiles;
}
public void setToDownloadDeafultFiles(boolean isToDownloadDeafultFiles) {
this.isToDownloadDeafultFiles = isToDownloadDeafultFiles;
}
private String fileNames;
private DataModelManager() {
}
public static DataModelManager getInstance() {
if (dataModelManager == null) {
synchronized (DataModelManager.class) {
if (dataModelManager == null) {
dataModelManager = new DataModelManager();
}
}
}
return dataModelManager;
}
private synchronized void addImageData(FrameData frameData) {
//Log.d("Frame Data","Start date "+frameData.getStartDate()+ " " +"end date "+frameData.getEndDate());
listFrameData.add(frameData);
}
public synchronized void parseData(String jsonStr) throws JSONException {
listFrameData.clear();
if (jsonStr == null) {
return;
}
List<String> listFileNames = new ArrayList<String>();
JSONArray jsonArr = new JSONArray(jsonStr);
int length = jsonArr.length();
for (int i = 0; i < length; i++) {
JSONObject jsonObj = jsonArr.getJSONObject(i);
dataModelManager.addImageData(new FrameData(jsonObj.optString("filename", ""), jsonObj.optString("start", ""), jsonObj.optString("end", ""), jsonObj.optString("filetype", ""), jsonObj.optString("playTime", ""), jsonObj.optBoolean("allDay", false)));
listFileNames.add(jsonObj.optString("filename", ""));
}
fileNames = listFileNames.toString();
}
public void setDefaultFileData(String jsonStr) throws JSONException {
JSONObject jsonObj = new JSONObject(jsonStr);
defaultFileName = jsonObj.optString("default_image", "");
screensaverName = jsonObj.optString("default_screensaver ", "");
}
#Override
public String toString() {
return fileNames.replace("[", "").replace("]", "") + "," + defaultFileName + "," + screensaverName;
}
public FrameData getFrameData(int index) {
return listFrameData.get(index);
}
public synchronized List<FrameData> getCurrentDataToShow() {
List<FrameData> lisCurrDataToShow = new ArrayList<FrameData>();
// for (FrameData fd : listFrameData) {//concurrent modification exception
//todo iterator test
Iterator<FrameData> iterator = listFrameData.iterator();
while (iterator.hasNext()) {
FrameData fd = iterator.next();
long currentTimeInMillis = java.lang.System.currentTimeMillis();
if ((currentTimeInMillis > fd.getStartDate().getTime() && currentTimeInMillis < fd.getEndDate().getTime()) || (fd.isAllDay() && DateUtils.isToday(fd.getStartDate().getTime()))) {
if (new File(ImageFrameActivity.ROOT_FOLDER_FILES + fd.getFileName()).exists()) {
lisCurrDataToShow.add(fd);
}
}
}
if (lisCurrDataToShow.size() == 0) {
lisCurrDataToShow.add(new FrameData(defaultFileName, null, null, null, String.valueOf(120), false));
}
return lisCurrDataToShow;
}
public String getCurrentFileNames() {
String currFileNames = "";
List<FrameData> currFrameData = getCurrentDataToShow();
for (FrameData data : currFrameData) {
currFileNames += "," + data.getFileName();
}
return currFileNames;
}
public ImageFrameActivity getImageFrameAct() {
return imageFrameAct;
}
public void setImageFrameAct(ImageFrameActivity imageFrameAct) {
this.imageFrameAct = imageFrameAct;
}
}
This is the only part of your question that is currently answerable:
If a threads is accessing getCurrentDataToShow() and another thread tries to access this function what will the function return?
It depends on whether you are calling getCurrentDataToShow() on the same target object; i.e. what this is.
If this is the same for both calls, then the first call will complete before the second call starts.
If this is different, you will be locking on different objects, and the two calls could overlap. Two threads need to lock the same object to achieve mutual exclusion.
In either case, this method is not changing the listFrameData collection. Hence it doesn't matter whether the calls overlap! However, apparently something else is changing the contents of the collection. If that code is not synchronizing at all, or if it is synchronizing on a different lock, then that could be a source of problems.
Now you say that you are not seeing ConcurrentModificationException's at the moment. That suggests (but does not prove) that there isn't a synchronization problem at all. And that suggests (but does not prove) that your current problem is a logic error.
But (as I commented above) there are reasons to doubt that the code you have shown us is an true reflection of your real code. You need to supply an MVCE if you want a more definite diagnosis.
I have implemented two member functions in the same class:
private static void getRequiredTag(Context context) throws IOException
{
//repeated begin
for (Record record : context.getContext().readCacheTable("subscribe")) {
String traceId = record.get("trace_id").toString();
if (traceSet.contains(traceId) == false)
continue;
String tagId = record.get("tag_id").toString();
try {
Integer.parseInt(tagId);
} catch (NumberFormatException e) {
context.getCounter("Error", "tag_id not a number").increment(1);
continue;
}
//repeated end
tagSet.add(tagId);
}
}
private static void addTagToTraceId(Context context) throws IOException
{
//repeated begin
for (Record record : context.getContext().readCacheTable("subscribe")) {
String traceId = record.get("trace_id").toString();
if (traceSet.contains(traceId) == false)
continue;
String tagId = record.get("tag_id").toString();
try {
Integer.parseInt(tagId);
} catch (NumberFormatException e) {
context.getCounter("Error", "tag_id not a number").increment(1);
continue;
}
//repeated end
Vector<String> ret = traceListMap.get(tagId);
if (ret == null) {
ret = new Vector<String>();
}
ret.add(traceId);
traceListMap.put(tagId, ret);
}
}
I will call that two member functions in another two member functions(so I can't merge them into one function):
private static void A()
{
getRequiredTag()
}
private static void B()
{
getRequiredTag()
addTagToTraceId()
}
tagSet is java.util.Set and traceListMap is java.util.Map.
I know DRY principle and I really want to eliminate the repeat code, so I come to this code:
private static void getTraceIdAndTagIdFromRecord(Record record, String traceId, String tagId) throws IOException
{
traceId = record.get("trace_id").toString();
tagId = record.get("tag_id").toString();
}
private static boolean checkTagIdIsNumber(String tagId)
{
try {
Integer.parseInt(tagId);
} catch (NumberFormatException e) {
return false;
}
return true;
}
private static void getRequiredTag(Context context) throws IOException
{
String traceId = null, tagId = null;
for (Record record : context.getContext().readCacheTable("subscribe")) {
getTraceIdAndTagIdFromRecord(record, traceId, tagId);
if (traceSet.contains(traceId) == false)
continue;
if (!checkTagIdIsNumber(tagId))
{
context.getCounter("Error", "tag_id not a number").increment(1);
continue;
}
tagSet.add(tagId);
}
}
private static void addTagToTraceId(Context context) throws IOException
{
String traceId = null, tagId = null;
for (Record record : context.getContext().readCacheTable("subscribe")) {
getTraceIdAndTagIdFromRecord(record, traceId, tagId);
if (traceSet.contains(traceId) == false)
continue;
if (!checkTagIdIsNumber(tagId))
{
context.getCounter("Error", "tag_id not a number").increment(1);
continue;
}
Vector<String> ret = traceListMap.get(tagId);
if (ret == null) {
ret = new Vector<String>();
}
ret.add(traceId);
traceListMap.put(tagId, ret);
}
}
It seems I got an new repeat... I have no idea to eliminate repeat in that case, could anybody give me some advice?
update 2015-5-13 21:15:12:
Some guys gives a boolean argument to eliminate repeat, but I know
Robert C. Martin's Clean Code Tip #12: Eliminate Boolean Arguments.(you can google it for more details).
Could you gives some comment about that?
The parts that changes requires the values of String tagId and String traceId so we will start by extracting an interface that takes those parameters:
public static class PerformingInterface {
void accept(String tagId, String traceId);
}
Then extract the common parts into this method:
private static void doSomething(Context context, PerformingInterface perform) throws IOException
{
String traceId = null, tagId = null;
for (Record record : context.getContext().readCacheTable("subscribe")) {
getTraceIdAndTagIdFromRecord(record, traceId, tagId);
if (traceSet.contains(traceId) == false)
continue;
if (!checkTagIdIsNumber(tagId))
{
context.getCounter("Error", "tag_id not a number").increment(1);
continue;
}
perform.accept(tagId, traceId);
}
}
Then call this method in two different ways:
private static void getRequiredTag(Context context) throws IOException {
doSomething(context, new PerformingInterface() {
#Override public void accept(String tagId, String traceId) {
tagSet.add(tagId);
}
});
}
private static void addTagToTraceId(Context context) throws IOException {
doSomething(context, new PerformingInterface() {
#Override public void accept(String tagId, String traceId) {
Vector<String> ret = traceListMap.get(tagId);
if (ret == null) {
ret = new Vector<String>();
}
ret.add(traceId);
traceListMap.put(tagId, ret);
}
});
}
Note that I am using lambdas here, which is a Java 8 feature (BiConsumer is also a functional interface defined in Java 8), but it is entirely possible to accomplish the same thing in Java 7 and less, it just requires some more verbose code.
Some other issues with your code:
Way too many things is static
The Vector class is old, it is more recommended to use ArrayList (if you need synchronization, wrap it in Collections.synchronizedList)
Always use braces, even for one-liners
You could use a stream (haven't tested):
private static Stream<Record> validRecords(Context context) throws IOException {
return context.getContext().readCacheTable("subscribe").stream()
.filter(r -> {
if (!traceSet.contains(traceId(r))) {
return false;
}
try {
Integer.parseInt(tagId(r));
return true;
} catch (NumberFormatException e) {
context.getCounter("Error", "tag_id not a number").increment(1);
return false;
}
});
}
private static String traceId(Record record) {
return record.get("trace_id").toString();
}
private static String tagId(Record record) {
return record.get("tag_id").toString();
}
Then could do just:
private static void getRequiredTag(Context context) throws IOException {
validRecords(context).map(r -> tagId(r)).forEach(tagSet::add);
}
private static void addTagToTraceId(Context context) throws IOException {
validRecords(context).forEach(r -> {
String tagId = tagId(r);
Vector<String> ret = traceListMap.get(tagId);
if (ret == null) {
ret = new Vector<String>();
}
ret.add(traceId(r));
traceListMap.put(tagId, ret);
});
}
tagId seems to be always null in your second attempt.
Nevertheless, one approach would be to extract the code that collects tagIds (this seems to be the same in both methods) into its own method. Then, in each of the two methods just iterate over the collection of returned tagIds and do different operations on them.
for (String tagId : getTagIds(context)) {
// do method specific logic
}
EDIT
Now I noticed that you also use traceId in the second method. The principle remains the same, just collect Records in a separate method and iterate over them in the two methods (by taking tagId and traceId from records).
Solution with lambdas is the most elegant one, but without them it involves creation of separate interface and two anonymous classes which is too verbose for this use case (honestly, here I would rather go with a boolean argument than with a strategy without lambdas).
Try this approach
private static void imYourNewMethod(Context context,Boolean isAddTag){
String traceId = null, tagId = null;
for (Record record : context.getContext().readCacheTable("subscribe")) {
getTraceIdAndTagIdFromRecord(record, traceId, tagId);
if (traceSet.contains(traceId) == false)
continue;
if (!checkTagIdIsNumber(tagId))
{
context.getCounter("Error", "tag_id not a number").increment(1);
continue;
}
if(isAddTag){
Vector<String> ret = traceListMap.get(tagId);
if (ret == null) {
ret = new Vector<String>();
}
ret.add(traceId);
traceListMap.put(tagId, ret);
}else{
tagSet.add(tagId);
}
}
call this method and pass one more parameter boolean true if you want to add otherwise false to get it.
public void compare(ArrayList list_old, ArrayList list_new) {
try {
Iterator<User> iterator_old = list_old.iterator();
Iterator<User> iterator_new = list_new.iterator();
//Check New User Is Added
while (iterator_new.hasNext()) {
Log.i("Test", "inside!");
User user_new = iterator_new.next();
boolean NEW = true;
while (iterator_old.hasNext() && NEW) {
User user_old = iterator_old.next();
if (user_new.getUsername().equals(user_old.getUsername())) {
NEW = false;
}
}
if (NEW) {
generateNotification(getApplicationContext(), user_new.getUsername() + " has been added.");
}
}
//Check User Is Removed
while (iterator_old.hasNext()) {
Log.i("Test", "inside");
User user_old = iterator_old.next();
boolean NEW = true;
while (iterator_new.hasNext() && NEW) {
User user_new = iterator_new.next();
if (user_old.getUsername().equals(user_new.getUsername())) {
NEW = false;
}
}
if (NEW) {
generateNotification(getApplicationContext(), user_old.getUsername() + " has been removed.");
}
}
} catch (Exception e) {
e.printStackTrace();
}
}
In this function I am comparing my old list with my new list.
The first while loop check, is any new user added and second while loop check, is any user is removed.
When I am running this application only my first while loop execute and it does not execute second while loop.
I checked with Log.i("Test", "inside!"); and I found it does not come inside my second while loop.
Please help
You need to re-initialize the iterator,
public void compare(ArrayList list_old, ArrayList list_new) {
try {
Iterator<User> iterator_old;
Iterator<User> iterator_new = list_new.iterator();
//Check New User Is Added
while (iterator_new.hasNext()) {
Log.i("Test", "inside!");
User user_new = iterator_new.next();
boolean NEW = true;
iterator_old = list_old.iterator();
while (iterator_old.hasNext() && NEW) {
User user_old = iterator_old.next();
if (user_new.getUsername().equals(user_old.getUsername())) {
NEW = false;
}
}
if (NEW) {
generateNotification(getApplicationContext(), user_new.getUsername() + " has been added.");
}
}
//initialize again
iterator_old = list_old.iterator();
//Check User Is Removed
while (iterator_old.hasNext()) {
Log.i("Test", "inside");
User user_old = iterator_old.next();
boolean NEW = true;
iterator_new = list_new.iterator();
while (iterator_new.hasNext() && NEW) {
User user_new = iterator_new.next();
if (user_old.getUsername().equals(user_new.getUsername())) {
NEW = false;
}
}
if (NEW) {
generateNotification(getApplicationContext(), user_old.getUsername() + " has been removed.");
}
}
} catch (Exception e) {
e.printStackTrace();
}
}
You're not resetting your iterators anywhere, so I don't think any of that code is working as you want it to. Your code would probably work and be much more readable if you used a for-each loop, which all Iterable classes support. This will avoid the need to create and reset iterators entirely.
for (User newUser : list_new) {
for (User oldUser : list_old)
// Compare
}
for (User oldUser : list_old) {
for (User newUser : list_new)
// Compare
}