views:

116

answers:

5

Hi,

I would like to multi-thread an application, however one library i'm using is not multi-thread capable (i don't know what's the right word ? synchronized ?).

What are my options ?

As far as i know there's nothing in between threads and processes (Runtime.exec) in java (no abstraction in the jvm to have something like an isolated "java process").

How would you deal with that ?

EDIT

Thanks for all the answer, once again, one level of indirection does the trick.

+11  A: 

You can ensure that the library in question is used only from a single thread at a time. If it contains instantiatable classes, one possibility is to hold these in thread local storage.

Or you can build a thread-safe wrapper around it.

These approaches could also be combined, e.g. you can wrap the library in a class (it would be a Facade in this case), which is not thread safe in itself, but whose instances you access from a single thread at a time.

Update: as @Wim pointed out, if the library manages global state, you must have a thread safe wrapper to ensure that changes are made visible between threads.

Péter Török
The first really implies the second. You need memory barriers to ensure cache coherency (each thread should have the same view on any global state in the library)
Wim Coenen
@Wim Very good point, thanks.
Péter Török
+6  A: 

I would create a Facade and not use the library directly. The Facade should then synchronize the connection/calls to the library.

Something like:

External Call    External Call    External Call
      |               |                |
      ----------------------------------             
                    Wrapper
                      |
                   Library

Update:

A Facade could be the wrong design pattern, because it is used to hide functionality. Wrapper should used as Design Pattern

Markus Lausberg
Facade is a design pattern for a slightly different problem - it should rather be a wrapper or Adapter.
Péter Török
A Facade should hide functionality and in this case other classes. May be you are right, it could also be a Wrapper.
Markus Lausberg
+2  A: 

I'd write a thin wrapper, where all relevant methods are synchronized, and which I'd then use everywhere in my code, instead of using the library's classes and methods directly. I'd evaluate first, for which parts of the library this is actually necessary.

Sometimes an alternative can be, to use separate instances of the library's objects for each thread. But in that case, the instances can't be shared among threads.

Chris Lercher
As an alternative to synchronized methods, you can make use of Locks (e.g. ReentrantReadWriteLock) to reduce bottlenecks, provided you know about the librarie's behaviour and can decide when to use ReadLock and WriteLock.
Sylar
@Sebastian: Can be done, if you know enough about the library. Maybe it should be noted, that if this leads to multiple lock objects, then obviously you'll also have to make sure to avoid deadlocks.
Chris Lercher
+3  A: 

Alot depends on the size of the library and what you are using it for. The first thing to do is evaluate where you may actually have concurrency issues. Just be cause you are using the library in more than one thread does not mean it can't be used in multiple threads. Look for items in the API that specifically say "this is not thread safe" and if you will be using that part of the API you will need to synchronize it yourself. The simplest solution is to create a wrapper class that synchronizes all of the methods. For an example look at the source from the collection utilities (such as Collections.synchronizedList, ect.).

M. Jessup
Note though that libraries _not_ designed with thread safety in mind rarely state explicitly "this is not thread safe" in their API doc :-(
Péter Török
+2  A: 

Look how similar problem is solved in Collections API. All collections are not thread safe by default.

But when you need a thread-safe collection you just get it with

Collections.synchronizedCollection(unsafeCollection)

The implementation is hidden from user and it's not a part of the API. You can go the same way.

Roman