• 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
  • Devaka Cooray
  • Ron McLeod
  • Paul Clapham
  • Liutauras Vilda
Sheriffs:
  • paul wheaton
  • Jeanne Boyarsky
  • Tim Cooke
Saloon Keepers:
  • Stephan van Hulst
  • Tim Holloway
  • Tim Moores
  • Mikalai Zaikin
  • Carey Brown
Bartenders:

practical applications of threads/synchronization

 
Ranch Hand
Posts: 275
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Hello. If anybody has a minute, I've been revisiting threads and synchronization. I've always been able to mess around and see how this stuff works in stand-alone programs, but i'm trying to place these concepts into the context of a true many clients-one server relationship. The one pratical example that seems to show the application of this is the single bank account and multiple concurrent atm transactions. I'm trying to get over defaulting to an entity bean and applying only synchronization and threads. From what I can gather, the following would have to be the case to synchronize the "shared oject", ie the bank account...

1. The methods in the shared object class that manipulates the pesistent account data has to be ~both~ synchronized and static...so all new object references will access the same method(s) that access the persistent data. is that right?

2. I am failing to see how threads work into concurrent multiple client-single server transactions...it's almost as if threads would be applied to a single instance (client) to keep multiple processes (as opposed to multiple clients as with synchronization) in order. Is that right? (i know it's not but i don't see how multiple client threads can all be scoped into a single shared class).

I would appreciate any input or whatever. I posted it here as opposed to the threads section because this might be more "text-book" than actual code/application. Thank you for reading this.
[ August 31, 2007: Message edited by: Tom Griffith ]
 
Ranch Hand
Posts: 133
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
�The methods in the shared object class that manipulates the pesistent account data has to be ~both~ synchronized and static...so all new object references will access the same method(s) that access the persistent data. is that right?�

If you make the method static in a separate object it will be a bottle-neck. Here is other option so you can work directly with the account object.

 
Ranch Hand
Posts: 1282
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
[Tom Griffith:]not but i don't see how multiple client threads can all be scoped into a single shared class

This is the code in my main() thread, which ..... uh, now I get your question.



A Thread of execution is not a class, duh. You could declare an instance of a class and then pass a copy of the reference to each Thread of execution. It is so difficult, until you get the subtlety of a machine sequence of instructions making it's way through your code. I believe the simple version of your answer is that each client instance/request/object gets run, but it only runs once. You do not, ahem, re-run, a class.

Once the data is recovered from the instance or the instance has done it's work, you can let the var go out of scope or set it to null if you need to dispose of the resources to which that reference is a handle - but I would be sure to think about what needs to be done and how to persist the data.

It is correct that both methods have to be synchronized, but static is not the answer to the design question you are posing. Dov Bulka has an extremely good book on what you are asking. Though it is written in c++, not Java, the issues and concepts translate with almost no pain or wonderment.


You have to have a way to test for completion. Join() and wait() are not solutions to monitoring a thread pool where any one may complete at any time. CyclicBarrier is not a solution to this design paradim, though you will hear it mentioned. On a true multi-processor machine, this is a proven design and will collaspe run-times to O log(t-total)

Henry's book is especially good for the question you are stepping into.

[ it can get really nasty ]
[ September 01, 2007: Message edited by: Nicholas Jordan ]
 
(instanceof Sidekick)
Posts: 8791
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Jaime Tovar's example correctly synchronizes two threads that are trying to access one account, at least on one method at a time. You could keep multiple instances of the Account object in a map keyed by account number. Account has no static bits, but the map will probably be a static "global" variable. It might need further synchronization when you add and remove accounts.

If you need to do more complex operations that involve several method calls, say transfer funds from one account to another, things get trickier. For example, another thread could take all the money out of acct1 between the balance call and the debit call:

Perhaps the best solution would be to put this code in Account:

If you have to compose several methods balance, credit & debig, you might want to synchronize on acct1 and acct2 for the duration which risks deadlocks.

Tom, does this seem like the right conversation so far? If so, we can tackle that deadlock bit next.
 
Nicholas Jordan
Ranch Hand
Posts: 1282
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Well if we make the Map static and key on the account number, we could then sync() on the account number, each entry in the map being an instance, Thus any number of threads could be working on the Map, but each account would be ( nomenclature for intact / integeral in oo ), and thus would scale well except for add/remove being disallowed under concurrency. That seems to be forefront to resoving deadlock detection and prevention ~ except for smaller textbook samples. Collection Iterators throw on concurrent modification == add/remove.

If the number of accounts needed is well known at program invocation, we could construct the map with a reasonable number of unused entires, but before taking this design approach we will need more design info from OP.
 
Tom Griffith
Ranch Hand
Posts: 275
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Hello. Thank you for the info everybody. I still kinda don't get why the synchronized methods aren't static, since they control persistent data and must belong to the class as opposed to instances. Wait a minute, the multiple customers don't create instances, do they?...they create a thread, ie call start(), on the ~imported~ class object, not an instance...right?

If that is the case, I can see why they don't have to be static...
 
Wanderer
Posts: 18671
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
[Tom]: I still kinda don't get why the synchronized methods aren't static, since they control persistent data and must belong to the class as opposed to instances.

Why must they belong to the class? I don't see that. I can write instance methods that submit SQL queries or updates to a database, for example. Databases are normally designed to allow multiple users at once, and there's no reason why two different users can't update different records in teh same table at the same time, for example. If you can do it with two users, why not two threads, each reading/writing data for a different instance of the Account class (using Jaime's example)?

Note - there is a potential problem with Jaime's code. Synchronizing on balance is unreliable, as that's a mutable reference to immutable class instances. I don't think there's actually a problem with the two methods that are there so far, but for more complex methods there could be trouble, especially if additional mutable fields are added. I think it's more reliable to synchronize on this, the current instance of the Account class. Or on some private final lock object, e.g.



Or instead of using an Object for the lock, you can use a Lock from JDK 5 or later. That's a longer topic though. There can be some advantages to syncing only on a privately-held instance, to prevent other threads from creating deadlock by syncing on something they shouldn't (namely, the same instance your thread is syncing on). That doesn't really come up very often, but when it does, it can be a bear.

[Tom]: Wait a minute, the multiple customers don't create instances, do they?...

They could, sure. Instances of what, I'm not certain at the moment, but whatever you mean, the answer is probably yes. If we're talking Accounts, some customers would be creating new Accounts, while others are loading or modifying existing Accounts.

[Tom]: they create a thread, ie call start(),

In many cases they might be using a thread pool, in which case an already existing thread will come to help them. But for simplicity we can imagine each customer starts a new thread, OK.

[Tom]: on the ~imported~ class object, not an instance...right?

I don't know what this means. What does imported mean here? Not the Java keyword import, right? What is a class object, if not an instance? Unless you mean an instance of the class Class, but I don't think so (and you should probably just ignore this sentence if it didn't immediately make sense, as it's probably not relevant).

If you're calling start() as in t.start(), then most likely the thing that you're calling it on (the thing referenced by the variable t) is an instance of the class Thread. You can call that an instance of class Thread, or an object of class Thread, either way. I tend to use 'instance' whenever I can, because 'object' seems to have additional meanings to different people that cause confusion. As is the case now, it seems.
 
Tom Griffith
Ranch Hand
Posts: 275
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
It kinda goes back to my original dilemma...if each customer (ATM) is calling a new instance of, say, the "transaction" class (it does jdbc or whatever with the database), where would the threads actually "meet" in order to implement sychronization? It seems to me the that individual threads would just live in each individual instance of "transaction"...
[ September 06, 2007: Message edited by: Tom Griffith ]
 
Stan James
(instanceof Sidekick)
Posts: 8791
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Let's say user 1 comes in on thread 1, creates a new DoSomeWork object. User 2 comes in on thread 2 and creates another DoSomeWork object. Everything is ok so far because they might work on different accounts. But we get to a point where we discover they are both working on the same account. That's where we have to synchronize.

It would seem obvious to synchronize on the Account object but there are some good reasons to prefer locking on something more private under the control of Account, like the "private final Object lock" as Jim just showed. That will force the two users through synchronized methods in single file.

Now in real life, I would be surprised to find a system that uses an Account object this way. Systems I've worked on would create an Account object for each user. Since they retrieve data form the database, they might have identical values. We'd use optimistic or pessimistic database locking to prevent overlapping updates.

On the other hand, I think the Forte 4GL language encouraged just what you suggest, managing concurrency in memory and writing to the database as an optional side effect. They even had rollback on in-memory object state if a transaction failed.

We still have this account transfer problem:

We really want to lock that whole sequence on both account1 and account2 so nobody can change either account in between our lines of code. We might be tempted to do this:

but that risks deadlock with somebody else trying to transfer from Account2 to Account1. Do you see why?

Is that answering the right question?
 
Tom Griffith
Ranch Hand
Posts: 275
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
ok...thank you everybody...i think i'm confused about something pretty basic...ignoring real world for a minute and stepping back...

user1 creates thread1 in instance1 of DoSomeWork

user2 creates thread2 in instance2 of DoSomeWork

how does thread1 and thread2 meet in Account without DoSomeWork1 and DoSomeWork2 each creating their own instances of Account?

A standalone executable simply creates two threads (thread1 and thread2), a single instance of DoSomeWork and a single instance of Account. It's the creating or accessing of the "common object", Account, by instance1 and instance2 of DoSomeWork which is getting me confused at the moment.

For instance, for servlets, i think i would probably set a context attribute to the Account object (the database connection and JDBC stuff)...meaning all DoSomeWork references that spawn threads could access the same "shared object" via getAttribute...and the threads are all synchronized, locked, "sleeped", notified, etc in Account...however, in terms of executables and packages, i don't see how to access/create a single Account object for say, two seperate executables each creating DoSomeWork instances...

thank you again...
[ September 06, 2007: Message edited by: Tom Griffith ]
 
Ranch Hand
Posts: 320
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
just a thought, but it depends on what you are synchronizing.... what you are "guarding"...

You have a bank, a bank manages accounts. You can deposit to an account, you can debit from an account, someone you gave a check to can draw on the account. The bank might give you a checkbook to write checks on the account. Both you and your spouse might need to write checks.

At the checkbook level you might want to imagine "synchronizing" access to the checkbook so that integrity of the checkbook balance is maintained.

At the bank level, they might want to "synchronize" access to the account balance to preserve integrity at that level.

So you might have a thread for each spouse, and a checkbook object.

You might have one or several threads for various transaction types or sources at the bank and an account object.

I'm not sure if all of this yammering in anyway addresses what you were looking for ......... it is a pretty high level look at the issue....
 
Stan James
(instanceof Sidekick)
Posts: 8791
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
How does thread1 and thread2 meet in Account without DoSomeWork1 and DoSomeWork2 each creating their own instances of Account?

They'd have to both get references to the same Account object instance. You could manage that with a static map of accounts, keyed by account number. That's the part I've never seen anybody do. (Maybe EJB Entity Beans do that? Took a class but never used them.)

More often I've seen concurrency issues - who updates when and in what sequence - handled in the database. That supports a cluster of several app servers connected to one database better then in-memory synchronization could.
 
Tom Griffith
Ranch Hand
Posts: 275
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Yeah, I've always used contaner managed ejb's for this kinda stuff but i wanted to check into thread/synchronization alternatives. I wanted to step back briefly to make sure I wasn't missing anyting on the object sharing part, becasue i could never really grasp what or how an infinite number of concurrent threads could share an object sans creating new references or as you said, copying the references. Like i said, i can see it in a j2ee model because you could create the shared object on startup and set it as a context attribute. I just wanted to make sure I wasn't missing anything...I'll mess around with the static map and also look further into the deadlock issue. Thank you everybody for the valuable information...it is very helpful.

[ September 07, 2007: Message edited by: Tom Griffith ]
[ September 07, 2007: Message edited by: Tom Griffith ]
 
Stan James
(instanceof Sidekick)
Posts: 8791
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
It would definitely be entertaining (in a very geeky way) to build live in-memory objects that are shared among users and threads and such. I was really intrigued by Forte's notion of rolling back object changes on transaction boundaries. I came across fairly negative about it because no matter how much geek fun it is, it might not be the best bang for my employer's buck.

See if Naked Objects addreses this kind of thing. They're surely having some geek fun.
 
Nicholas Jordan
Ranch Hand
Posts: 1282
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
[Tom Griffith:] ... still kinda don't get why the synchronized methods aren't static,...

This may be addressed several times in the discussion, but I really went through the grinder on this in a post I made awhile back and now it is extremely easy for me.

You have code, static or not.

You have a machine.

The machine has a processor, which even in the virtual machine will have some way of locating the next instruction. No matter how many instructions you have sitting there, waiting, nothing happens until some form of an instruction pointer brings that pattern onto a processor somewhere. There are two cases:
Single Processor: Some sort of scheduler decides what happens next.
Multiple Processor: Some sort of scheduler decides what happens next.
Patterns in RAM - brought into the processor:
00110110 1101110 0001101 0101110 001101110
00110110 1101110 0001101 0101110 001101110 <-- instruction pointer 1
00110110 1101110 0001101 0101110 001101110 <-- instruction pointer 2
00110110 1101110 0001101 0101110 001101110
00110110 1101110 0001101 0101110 001101110

What happens when instruction pointer one overruns instruction pointer two ?

Threads are the machine, it's self, in operation. Code is a pattern you write that the machine tries to follow.

See: Failure mode of two reference calls to one thread in which I ultimately went back and admitted I had the question wrong.

See also:A question from Java Concurrency in Practice

[HW: Can you put that two cooks in the kitchen thing somewhere so that it can be found easily for posts such as this ? Threading is difficult to visualize as the machine in operation, not the code on the page.]

[Fixed link - Dave]
[ September 16, 2007: Message edited by: David O'Meara ]
 
Joel Salatin has signs on his property that say "Trespassers will be Impressed!" Impressive tiny ad:
a bit of art, as a gift, the permaculture playing cards
https://gardener-gift.com
reply
    Bookmark Topic Watch Topic
  • New Topic