File APIs for Java Developers
Manipulate DOC, XLS, PPT, PDF and many others from your application.
http://aspose.com/file-tools
The moose likes Developer Certification (SCJD/OCMJD) and the fly likes Multi-threading programming: we do not need lock() unlock() at all Big Moose Saloon
  Search | Java FAQ | Recent Topics | Flagged Topics | Hot Topics | Zero Replies
Register / Login
JavaRanch » Java Forums » Certification » Developer Certification (SCJD/OCMJD)
Bookmark "Multi-threading programming: we do not need lock() unlock() at all" Watch "Multi-threading programming: we do not need lock() unlock() at all" New topic
Author

Multi-threading programming: we do not need lock() unlock() at all

Walter Tang
Greenhorn

Joined: Aug 13, 2004
Posts: 25
Originally posted by Walter Tang:
Hello everyone,
Spring break gave me chance to re-work on URLybird. After think awhile, I strongly believe, we do not need lock unlock.

Generally, there are two choices for designing the server side:
(1) One Data object that is shared by all threads (clients)
In which case, we only synchroniz the Data object. Only one client
, at a time can access database file. Only need to concern lock.

(2) Each thread (Client) has its only Data object.
In which case, two or more Data objects exist at same time, but there is only one database file(static) object that Data can manipulate. In this case, we have to syncrhonize the database file to make sure there is only one thread accessing the file at a time.

In both case, only one thread can access the file at a time. Why dont we keep thing simpler and clearer, just synchrinze the Data.java

Comments are strongly welcomed.
Happy New Year
Jing
[ January 05, 2005: Message edited by: Walter Tang ]

SCJP
peter wooster
Ranch Hand

Joined: Jun 13, 2004
Posts: 1033
Originally posted by Walter Tang:
Hello everyone,
Spring break gave me chance to re-work on URLybird. After think awhile, I strongly believe, we do not need lock unlock.

Generally, there are two choices for designing the server side:
(1) One Data object that is shared by all threads (clients)
In which case, we only synchroniz the Data object. Only one client
, at a time can access database file. Only need to concern lock.

(2) Each thread (Client) has its only Data object.
In which case, two or more Data objects exist at same time, but there is only one database file(static) object that Data can manipulate. In this case, we have to syncrhonize the database file to make sure there is only one thread accessing the file at a time.

In both case, only one thread can access the file at a time. Why dont we keep thing simpler and clearer, just synchrinze the Data.java

Comments are strongly welcomed.
Happy New Year
Jing


You definitely need logical resource lock and unlock, not implementing it is an automatic failure. There are two types of locking and you need both.

1) synchronization on the file or table that contains the database records. This is handled by the kind of locking you are discussing. This sort of locking prevents simultaneous access to the database. You don't want to expose this across a network.

2) logical record locking. This is not tied to the database file but rather to an arbitrary numeric resource that just happens to represent a record number. This locking doesn't stop other clients from accessing the database, it just stops them from locking the same resource. You can expose this across a network to a client. This is similar to the Oracle operation Select For Update.


The lock and unlock methods relate to 2).
Jim Janssens
Ranch Hand

Joined: Sep 24, 2004
Posts: 210
Well I believe that TS is correct. The logical locking is really not necesairy. You can handle all the locking just by synchronizing the reads/writes on the RandomAccessFile.

This way you can guarantee that:

-No mulitple creates occur at the same time, and thus will not use the same record number.
-Updates are atomic, so you can guarantee consistency. If thread A is updating record 1 , then thread B cannot update the same record because thread A is allready owning the lock on the RAF
-Reads are also atomic, if thread A is reading record 1 and thread B wants to update record 1, then either thread A will read first, or thread B will update first, but there will be no updating while trhead A is reading because of the synchronization.
-Deletes are atomic, because of the RAF synchronization.

Ofcourse, this requires that some of the code is put inside the synchronized brackets. Such as getting the next free record number etc, if that occurs outside the brackets then the same record number can be used twice.

I realize that this is certainly no performant way (neither a good practise)to choose. But I'm sure it will work. Also, you are required to use logical locking for the assigmnent, because it is a must (!) .

Ofcourse, if someone thinks that I'm wrong, please comment !
Frans Janssen
Ranch Hand

Joined: Dec 29, 2004
Posts: 357
I found one important case why I do need record locking (I have the B&S assignment by the way):

When a client books a contractor, I use the following procedure:

1. lock the record
2. read the record to verify that it is not booked
3. update the record if it was indeed not booked
4. unlock the record

The verification that the record is not booked makes sense only when the record is locked. If the record were not locked, the following chain of events could occur when two clients attempt to book the same contractor concurrently:

1. client A reads record; the record is not booked
2. client B reads record; the record is not booked
3. client A updates record
4. client B updates record; booking of client A is lost!

This cannot be solved by synchronizing on the database access methods (which I also do, to prevent that a record that is being written, is being read simultaneously), unless one synchronizes on business methods like bookContractor(), that wraps the read and update methods into an atomic-like action. But since I am implementing a fat client, this is not an option for me.

Frans.


SCJP 1.4, SCJD
Jim Janssens
Ranch Hand

Joined: Sep 24, 2004
Posts: 210
Originally posted by Frans Janssen:
I found one important case why I do need record locking (I have the B&S assignment by the way):

When a client books a contractor, I use the following procedure:

1. lock the record
2. read the record to verify that it is not booked
3. update the record if it was indeed not booked
4. unlock the record

The verification that the record is not booked makes sense only when the record is locked. If the record were not locked, the following chain of events could occur when two clients attempt to book the same contractor concurrently:

1. client A reads record; the record is not booked
2. client B reads record; the record is not booked
3. client A updates record
4. client B updates record; booking of client A is lost!

This cannot be solved by synchronizing on the database access methods (which I also do, to prevent that a record that is being written, is being read simultaneously), unless one synchronizes on business methods like bookContractor(), that wraps the read and update methods into an atomic-like action. But since I am implementing a fat client, this is not an option for me.

Frans.


Well, I don't want to disapoint you (in fact, I'm also using the logical locking for the same reasons) but you really don't need it.

When you synchronize on the RAF you'll get the exact result:

-Thread A wants to book contractor x
-Thread A goes into the synchronized(RAF) block
-Thread B wants to book contractor x
-Thread B has to wait until A leaves the synchronized block
-Thread A checks if the contractor is already booked (inside the synchronized brackets)
-Thread A books the contractor (=writes the owner field) because he is not booked yet
-Thread A releases the lock
-Thread B gets the lock on the RAF and enters the synchronized block
-Thread B checks if the contractor is already booked (inside the synchronized brackets) and finds out he is already booked

Thats is. By synchronizing on the RAF you can do it all, you just have to think about doing the proper checks inside the synchronized(RAF) block...
Frans Janssen
Ranch Hand

Joined: Dec 29, 2004
Posts: 357
Originally posted by Koen Serneels:



When you synchronize on the RAF you'll get the exact result:

-Thread A wants to book contractor x
-Thread A goes into the synchronized(RAF) block
-Thread B wants to book contractor x
-Thread B has to wait until A leaves the synchronized block
-Thread A checks if the contractor is already booked (inside the synchronized brackets)
-Thread A books the contractor (=writes the owner field) because he is not booked yet
-Thread A releases the lock
-Thread B gets the lock on the RAF and enters the synchronized block
-Thread B checks if the contractor is already booked (inside the synchronized brackets) and finds out he is already booked

Thats is. By synchronizing on the RAF you can do it all, you just have to think about doing the proper checks inside the synchronized(RAF) block...


Koen,

I agree that you don't need record locking if you do the check and the update inside a single synchronized block.

However, that can only be done if the server offers this as an atomic action to the clients. In that case you probably have a thin client where the server offers functionality on business level, e.g. "book contractor".

In my design I have chosen for a fat client where all the business logic is in the clients. The server exposes only the methods as defined in the given DBMain interface. The check is done with a call to read() and the actual booking with a call to update(). IMHO there is no simple way to make the server handle these two calls in an uninterruptable session, other than using some sort of locking system.

So my statement still stands that for those people who choose a fat client approach (hands up all who did this! ), record locking is a necessity.

Perhaps we should even regard this as a hint from Sun that the fat client is the preferred design solution, since otherwise the whole record locking functionality indeed doesn't make much sense?

Frans.
Walter Tang
Greenhorn

Joined: Aug 13, 2004
Posts: 25
Hi Peter,
Thanks for your reply.

Originally posted by peter wooster:


You definitely need logical resource lock and unlock, not implementing it is an automatic failure. There are two types of locking and you need both.

1) synchronization on the file or table that contains the database records. This is handled by the kind of locking you are discussing. This sort of locking prevents simultaneous access to the database. You don't want to expose this across a network.

2) logical record locking. This is not tied to the database file but rather to an arbitrary numeric resource that just happens to represent a record number. This locking doesn't stop other clients from accessing the database, it just stops them from locking the same resource. You can expose this across a network to a client. This is similar to the Oracle operation Select For Update.


The lock and unlock methods relate to 2).


Yeah, I agree with you. We have to make sure one client get/modify/update a record at a time. Thus, we need to lock and then unlock that record.

However, as Koen already pointed out, if we synchronize the Data object, which is the class manipulating database file, we do not need to worry about lock and unlock at all. In this case, only one client can use the Data object to manupulate database file at a time.

Therefore, either we can synchronize at Data.java level or syncrhonize the record, the effect is the same --- only one thread can access data file at a time.

Not implementing lock and unlock, surely, will result in auto failure. I am not conveincing others to not implements these two. Just because I am sort of confused on this, never mind.
Matt Sheehan.
Ranch Hand

Joined: Oct 08, 2004
Posts: 63
Originally posted by Walter Tang:
Hi Peter,
Thanks for your reply.



Yeah, I agree with you. We have to make sure one client get/modify/update a record at a time. Thus, we need to lock and then unlock that record.

However, as Koen already pointed out, if we synchronize the Data object, which is the class manipulating database file, we do not need to worry about lock and unlock at all. In this case, only one client can use the Data object to manupulate database file at a time.

Therefore, either we can synchronize at Data.java level or syncrhonize the record, the effect is the same --- only one thread can access data file at a time.

Not implementing lock and unlock, surely, will result in auto failure. I am not conveincing others to not implements these two. Just because I am sort of confused on this, never mind.

Peter and Frans are right. There is a clear explanation of this near the end of this thread in part of which Andrew says:
The logical record locking and having thread safe access to the data file serve two totally different purposes.


Matt
[ January 04, 2005: Message edited by: Matt Sheehan. ]
peter wooster
Ranch Hand

Joined: Jun 13, 2004
Posts: 1033
If you are using the "thin client" model, you could get away without doing the logical record locking. I don't believe that the thin client model is actually a valid solution to this project, even though a few people have passed using it. The requirements are very explicit that this should be a traditional client server system, that the server should do database work and the client should do the rest. Putting the business logic on the server simplifies a vast amount of the problems.

If you put the business actions such as "book" on the server then you don't need to do logical record locking and can simply synchronize on the random access file for the whole book method. If you put the book action on the client you will need the logical record locking.
Jim Janssens
Ranch Hand

Joined: Sep 24, 2004
Posts: 210
Originally posted by Frans Janssen:


Koen,

I agree that you don't need record locking if you do the check and the update inside a single synchronized block.

However, that can only be done if the server offers this as an atomic action to the clients. In that case you probably have a thin client where the server offers functionality on business level, e.g. "book contractor".

In my design I have chosen for a fat client where all the business logic is in the clients. The server exposes only the methods as defined in the given DBMain interface. The check is done with a call to read() and the actual booking with a call to update(). IMHO there is no simple way to make the server handle these two calls in an uninterruptable session, other than using some sort of locking system.

So my statement still stands that for those people who choose a fat client approach (hands up all who did this! ), record locking is a necessity.

Perhaps we should even regard this as a hint from Sun that the fat client is the preferred design solution, since otherwise the whole record locking functionality indeed doesn't make much sense?

Frans.


Hmm, thats true, I am using a thin client. And I think you are correct.
I'm doing the update check (the read followed by the update) in my database facade at the service side. The scenario is like this:

- Client calls update()
- Server: update calls lock(recno)
- Server: update does a read to insure consistency
- Server: updates if still consistent
- Server: update calls unlock(recno)
- Client gets updated situation as verification

Your scenario will probably be:

- Client calls lock(recno)
- Client calls read() to to consitency check
- Clients calls update() if still consitent
- Client calles unlock(recNo)

So in your case the logical lock and unlock makes more sense. However, the thin client is just an approach as the fat client. In this strategy the logical locking seems to be trivial, but never the less it is there and it works. If there is the need to switch to a fat client, its just a matter of moving some code around...
Walter Tang
Greenhorn

Joined: Aug 13, 2004
Posts: 25
Thanks for everyone's help, now it is much clearer. For locking, there are two different issues:
1) Dirty data
In this situation, thread A checked a record,andfind record is
available. However, thread B find the record is also avaiable just
before thread A book the record. There infordation thread B get
is dirty (not updated)

check() -> book() thread A
check() -> book() thread B
solution: lock() and unlock

2) Data corruption
In which situation, two threads are attempting to access the
file at the same time.

Solution: synchronization
[ January 05, 2005: Message edited by: Walter Tang ]
 
I agree. Here's the link: http://aspose.com/file-tools
 
subject: Multi-threading programming: we do not need lock() unlock() at all
 
Similar Threads
Design and questions
Defence using current thread as client's ID
Data Locking with a DB File.
does the Data class have to be a singleton?
Q on Concurrent Accessing