I want to get an object by a static factory method, such as
Person p = Person.fromName("Jack");
class Person {
public static Person fromName(String name){
return new Person(name);
}
}
but fromName() method is not thread safe, (fromName() is just an example, this kind of method will occur error when it's running in my program) however, it's inefficient if synchronized this method because multiple threads should call this method concurrently. Is there any suggestion to fix it?
If you've got code which is unsafe to execute in multiple threads concurrently, but you want to call it from multiple threads, it sounds like you really only have two options:
Make it thread-safe
Take the hit of serializing calls via synchronization
You haven't given any information which would suggest which of these is most appropriate in your situation. (Have you measured the performance hit of synchronization? Have you tried to make it thread-safe?)
Your problem seems unsolvable when you say that
A) the method is not thread safe (thus needs to be used in a synchronized manner) and
B) it may not be synchronized due to efficiency reasons.
The only advice I can give you is to perform as fine grained syncrhonization as possible, i.e. only synchronize over thread-unsafe parts of the method.
If for instance statement S1 needs to be performed atomically together with S2 you could instead of doing
public synchronized static Person fromName(String name){
...
S1;
S2;
...
return ...;
}
do
public static Person fromName(String name){
...
synchronized (lock) {
S1;
S2;
}
...
return ...;
}
Related
I want to ask you for help with advanced synchronization.
I have class like this:
public class Manager{
private ClassMatcher classMatcher;
public ClassMatcher getClassMatcher(){
return this.classMatcher;
}
public void setClassMatcher(ClassMatcher classMatcher){
this.classMatcher = classMatcher;
}
}
Object Manager can be called from more Threads, so methods: getClassMatcher and setClassMatcher should be synchronized.
But in that case method getClassMatcher can be accessed only by one Thread in the same time.
Is there some way how to solve it ? Well perhaps I can use Locks or AtomicReferences.
Thank you for any advice, it will be really helpful
You don't need to synchronize those methods, but class ClassMatcher should be thread-safe.
Call get or set won't cause problems in your case because set method only replaces the reference of class member to a new object.
I can't see any reason why you need synchronization in such example because your accessors don't do much work with shared state which really can cause some concurrent issues.
For instance, here we have race condition and synchronization needed:
public int get() {
if (a == b) {
return a;
} else {
return b;
}
}
PS: as #shmosel mentioned you may mark your variable as volatile to be sure that you get() the most actual version of your classMatcher
I have seen usage of synchronized block by this so far but recently I learned that using dummy object is preferable. I found the following topic related to this.
Java synchronized method lock on object, or method?
As a summary, in the code below, two different object can not run addA and addB concurrently as both uses this for lock.
private int a;
private int b;
public synchronized void addA(){
a++;
}
public synchronized void addB(){
b++;
}
I am confused if I use dummy object for lock, what will be different if I use the line below in both method to synchronize? Because still they would have same lock.
synchronized(dummyObject){
...
}
So what it means that I should have two different dummy object for each method to use with sycnhronized as?
public void addA(){
synchronized(dummyObj1){
a++;
}
}
public void addB(){
synchronized(dummyObj2){
b++;
}
}
That is exactly the point of lock objects - you can use different locks for different operations. Assuming it makes sense to run addA and addB concurrently (and from the looks of it - it definitely does), you should indeed have two separate locks, one for each method.
You are correct. In this case you need two different objects to synchronize on them separately.
For locking purpose the easiest way is to create Object objects.
Object lock1 = new Object();
Object lock2 = new Object();
I'm learning about Java multi-threading and came across a very good tutorial online. But I am not sure if I understand a part where the writer explains about thread-safe objects, variables and such. To quote him,
public void someMethod(){
LocalObject localObject = new LocalObject();
localObject.callMethod();
method2(localObject);
}
public void method2(LocalObject localObject){
localObject.setValue("value");
}
...the whole method someMethod() is thread safe. Even if the LocalObject instance is passed as parameter to other methods in the same class, or in other classes, the use of it is thread safe. The only exception is of course, if one of the methods called with the LocalObject as parameter, stores the LocalObject instance in a way that allows access to it from other threads.
I understand why the LocalObject instance is thread-safe. But I would like to see an example of the exception case (the last line in the above block quote). If someone could write a code snippet that fits what's written in the last line, that would be very helpful. Thank you!
public class SomeClass {
private LocalObject cachedLocalObject;
public void someMethod() {
LocalObject localObject = new LocalObject();
localObject.callMethod();
method2(localObject);
}
public void method2(LocalObject localObject) {
this.cachedLocalObject = localObject;
localObject.setValue("value");
}
public LocalObject getCachedLocalObject() { return cachedLocalObject; }
}
The combination of caching the object in method2() and then exposing it for external use in getCachedLocalObject() breaks threadsafety: some other thread can use getCachedLocalObject() to obtain and modify cachedLocalObject.
The contrast is demonstrated in the next part: "Object Members". As long as the object remains local to thread, it will be inherently thread-safe. But as soon as the reference is assigned to an object's field, any thread with a reference to the parent object can gain access to its fields, rendering them (potentially) not thread-safe.
If I have a class Foo
public class Foo implements Serializable, Cloneable {
public Foo() {}
protected String s;
protected int n;
public Foo clone() {
return (Foo) super.clone();
}
public String getS() {
return s;
}
public void setS(String s) {
this.s = s;
}
public String getN() {
return n;
}
public void setN(int n) {
this.n = n;
}
}
And it's used in MyClass and the handler is passed to two thread A and B what appens if at the same time thread A try to clone the handler and thread B try to change a public variable of the handler?
E.g.
Foo Class
s = "Hello"
n = "42"
This class is passed to A and B that run at the same time.
A wants clone Foo Class and after 1 µs B wants change n to 43.
The clone result will be s = "Hello" and n = "42" || n = "43"?
More simpler: super.clone() is thread safe or I have to use lock or synchronized? In case I have to use lock or synchronized which is the best way to use them?
You are slightly misusing the term "thread-safe". It does not mean "synchronized", and that's apparently how you are using it. No amount of synchronization can prevent implementation errors from breaking thread safety. As an example, any code you wrote which mutates the object while not holding any lock will clearly violate thread safety of the object, and there is nothing a library method like Object.clone can do about that.
Ultimately, thread safety is always in the hands of the implementor and Object.clone() will not do anything to make that harder for you: all it does is read the state of the current object and copy it to the new object. It does not publish that new object.
clone is not specifically described as thread-safe, which means it's not. If one thread is cloning the object while another thread is changing it, the clone can end up in an inconsistent state.
You could grab a lock in your clone function, but much better would be to grab it in the code which calls clone.
No it is not thread safe if two threads are trying to execute this method over the same instance of Foo.
You should create a mutex using this instance .For example place the code which executes this clone method in synchronized(fooInstance) block.
I am studying Java concurrency right now. I have a question about synchronized and locks.
For any mutable data, we should put all the method accessing the data in the same lock.
But, what does same lock mean?
Example:
public class SynchronizedInteger{
private int value;
public synchronized int get(){return value;}
public synchronized void set(int value){this.value=value;}
}
So, my question is why this two methods are in the same lock? I know they are, but I would like to know why? And, does it mean that all the synchronized methods in the class are in the same lock?
Edit:
so, if I added one more method to the class:
public synchronized void printOneToHunder(){
for(int i=0;i<100;i++) System.out.println(i);
}
This method will also be included into same block as setter and getter? So, other thread cannot run this method when there is one thread using either setter or getter?
And, what if I change the class to below:
public class SynchronizedInteger{
private int value1;
private int value2;
public synchronized int get1(){return value1;}
public synchronized void set1(int value){this.value1=value1;}
public synchronized int get2(){return value2;}
public synchronized void set2(int value){this.value2=value2;}
}
For my understanding right now, only one thread can call these method at one time. So what's the way to make one thread can modify value1 and the other thread to modify value2???
Thanks a lot for your kindly clarifications!!!!
All non-static methods that you declare synchronized behave essentially as if the code was:
public synchronized int get() {
synchronized(this) {
// the method code
}
}
i.e. there is an implicit lock on this taken. So all non-static synchronized methods will lock the instance on which they are called.
Static synchronized methods take a lock on the class object itself, rather than an instance of that class.
Yes, your two methods are using the same lock.
The synchronized keyword without parameter is implicitly translated to syncrhonized(this), which is the same object for both methods.
In order for two blocks to have "the same lock" in java, it means that they are both using the same object as a lock. And as I said, in your case, both methods are using this as the lock object.
When you declare a method synchronized, it means that synchronization is on the particular instance for which the method is being invoked.
But you have other ways for synchronization.
Synchronized blocks:
synchronized(someLockedObj){somecode}
Lock-Objects:
Lock lock = new ReentrantLock(); lock.lock(); lock.unlock();