• Post Reply Bookmark Topic Watch Topic
  • New Topic
programming forums Java Mobile Certification Databases Caching Books Engineering Micro Controllers OS Languages Paradigms IDEs Build Tools Frameworks Application Servers Open Source This Site Careers Other Pie Elite all forums
this forum made possible by our volunteer staff, including ...
Marshals:
  • Campbell Ritchie
  • Jeanne Boyarsky
  • Ron McLeod
  • Paul Clapham
  • Liutauras Vilda
Sheriffs:
  • paul wheaton
  • Rob Spoor
  • Devaka Cooray
Saloon Keepers:
  • Stephan van Hulst
  • Tim Holloway
  • Carey Brown
  • Frits Walraven
  • Tim Moores
Bartenders:
  • Mikalai Zaikin

how can you avoid nested synchronization

 
Greenhorn
Posts: 7
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
in lock() method we need to check records validity, make sure the record is not deleted before locking it.
I found I can't avoid to use nested synchronization, please read following code , how did you implement your lock method? can you avoid nested synchronization? thanks.
 
author and jackaroo
Posts: 12200
280
Mac IntelliJ IDE Firefox Browser Oracle C++ Java
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Hi Wayne,

While you should always try to avoid nested synchronization, sometimes it is not possible to avoid it totally. As long as you always nest in the same order you should be OK.

But some alternatives for you: You could have a local collection containing the list of deleted records which can only be modified while you own the mutex on lockmap. So you could then just check the deleted record in that collection without ever going to the RAF (although this requires you to read the entire RAF at some point).

Alternatively, within your lock method you could add the lock details to the lockmap and release your mutex on it. Then go and check the validity of the record and, if it is not valid, silently unlock the record.

Regards, Andrew
 
Wayne John
Greenhorn
Posts: 7
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator

But some alternatives for you: You could have a local collection containing
the list of deleted records which can only be modified while you own the mutex on lockmap.
So you could then just check the deleted record in that collection without ever going to the RAF




Hello Andrew :
thank you for your reply.

acutally I had the same idea before, it's similar with your comments.
but, I don't think I can use lockmap as mutex .I write down the code below,
could you read it and give me some suggestion, I'll really appreciate for it!



[ December 14, 2005: Message edited by: Wayne John ]
 
Ranch Hand
Posts: 918
IntelliJ IDE Java Linux
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Hi, John


If you choose to combine the lock mechanism with the IO feature you can land easly to the nested block probelm. This is not so nice but if you know the nest order you can avoid a deadlock.
You can also use the same look for both, but this can be a little bit to much.

An othre way to avoid this is to separate the lock mechanism from the IO features - two seperate classes. In this case you can synchronize separate all the read/write operations.

One more remarc to your last statement


thread could slice out from here, so this record could be deleted by other thread then this thread read a deleted record!



IMHO this is not a real problem. You can see it like this, even if your whole method will be atomic and it always retun the right records is still not enought, after you exit them metohd and you try to use the result (let's say to display it) an other thread can perform a delete. The read provides only a "view" from a specific moment(time), in the next moment the system may change.


Regards,
Mihai.
[ December 16, 2005: Message edited by: Mihai Radulescu ]
 
Wayne John
Greenhorn
Posts: 7
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
hello Mihai:
thank you for the reply.
maybe I wrote too much in my last post, could you read my following post and give me an answer . thank you.

void deleteRecord(int recno) throws Exception{
synchronize(raf){
try{ ......... delete a record from dbfile
} catch(IOException){
throws Exception
}
}............. //even this record was deleted from dbfile ,but thread could slice out in here, //and another thread could read this record which has already been deleted. // is this a big problem???

addDeletedRecords(recno);//this function will add one deleted record to arraylist.

}


in read() method, we also need to check record validity,
void read( recno) throws Exception{
//check if record has been deleted;
if(isDeletedRecord()){ throw Exception; }
...........> thread could slice out from here, so this record could be deleted by other thread then this thread read a deleted record! is this a matter? it's not dirty read, just stale read ,seems many people just ignore this problem. or we also need to put isDeletedRecord() into synchronize(raf) block?

synchronize(raf){ doing read process }

}
 
Mihai Radulescu
Ranch Hand
Posts: 918
IntelliJ IDE Java Linux
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Hi,

I don't realy understand your question.Can you be a little bit more specific.

Here is what I understant.

Your code snipplets are from your IO layer, by io layer I mean the class for read/search/write ?
If the answer is yes why you don't synchronize with same lock(on instance by example) all the IO methods? In this way delete and create are atomic, this can spare you from a lot of problems(one is nested synchronized blocks).

About the read probelm I already explain in my last post("One more remarc to your last statement ........" ).

I hope this hepl.

Regards,
Mihai
[ December 16, 2005: Message edited by: Mihai Radulescu ]
 
Wayne John
Greenhorn
Posts: 7
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Hello Mihai:
thank you for the reply.
yes,the code snipplets is from IO layer. acutally I write one class called "DBFileAccess" for io processing, the Data class need to call this class to finish read , delete ,update operation.

if I put them into same synchronized block,
that means when I write function isDeletedRcord(), I have to use synchronize(raf){}block again . like this:
public void isDeletedRecord(int recno){
synchronize(raf){
return arraylist.contain(new Integer(recno));

}

}
I think it's low performance , because in data class , all read , update method need to call this method . and in lock() method I also need to call this method, so, the lock method will block file io operation.

if I use arraylist as mutex, when I call isDeletedRecord() method it won't block IO operation. I got confused about this.
Maybe I should listen your suggestion, make the things simple.
 
Ranch Hand
Posts: 209
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Andrew said


While you should always try to avoid nested synchronization, sometimes it is not possible to avoid it totally. As long as you always nest in the same order you should be OK.



I guess we need 1) to determine what objects need to be accessed in a multi-thread safe fashion; 2) and then determine how it can be achieved.
That is what I've got so far:

1. For the logical locking (ie record locking) there is a static lockedRecords map that stores key/value pairs where the key is a record number and a value is a client who has locked it

2. For the physical locking (ie file locking) there is a static dbFile object that provides read/write access to the database file (it delegates read/write tasks to the instance of RAF)

3. For the record cache there is static recValidFlags list in which an element position represents a record number and the actual element is a record validity flag (of byte type, either Data.VALID_RECORD or Data. DELETED_RECORD). The actual number of elements in this list represents a total number of records in the file (both deleted and valid).
recValidFlags is initially populated on the start up (when the database file is chosen by the user) and is then maintained by the Data instances.
Collections.synchronizedList(new ArrayList<Byte>()) method is used to create a List instance used for this cache, which makes access to recValidFlags methods multi-thread safe.
The recValidFlags cache is used for a) checking whether the record exist; b) determining in what position to create a new record.
The recValidFlags cache is modified when a) a new record is created ; b) when a record is deleted

Data instances will synchronize on these three static objects ( ie lockedRecords / dbFile / recValidFlags ) in the following manner:

Data#read(int recNo)



Data#create(String[] record)



Data#lock(int recNo)



Data#delete(int recNo)


All comments are welcome.


[ December 19, 2005: Message edited by: Alex Sharkoff ]
 
reply
    Bookmark Topic Watch Topic
  • New Topic