I have a method with a synchronization statement on an "non-this" object
class Some_Class {
public A s = new A();
public void method_A() {
synchronized(s) {
....
}
}
}
Can I instead extend class A and synchronize as follows:
class B extends A {
public A a;
public B(A a) {
this.a = a;
}
public synchronized void some_m() {
...
}
}
class Some_Class {
public A s = new A();
public void method_A() {
B b = new B(s);
b.some_m();
}
}
Are these two synchronizations equivalent?
No, they're not equivalent. This method here:
public synchronized void some_m() {
...
}
Does the same as this one:
public void some_m() {
synchronized(this) {
...
}
}
Or in other words
Your first code option synchronises on an instance of A in Some_Class (a class member, visible to everyone).
Your second code option synchronises on the instance of B within Some_Class.method_A() (a local variable, invisible to the outside of that method)
No, they are not equivalent. In second case you actually don't have synchronization at all. Because some_m method synchronized on instance of B. So you create local instance of B and call method on it. This method is synchronized only on this local instance of B and other threads don't care about it and can do whatever they want with s because it's not synchronized.
Can you describe what you want to achieve?
Synchronized block synchronizes the whole object while synchronized method synchronizes just that method. In the second case, some thread can still access other non-synchronized methods of the object.
Related
So I have the following scenario (can't share the actual code, but it would be something like this):
public class Test
{
private Object obj;
public void init()
{
service.registerListener(new InnerTest());
}
public void readObj()
{
// read obj here
}
private class InnerTest implements Listener
{
public synchronized void updateObj()
{
Test.this.obj = new Object();
// change the obj
}
}
}
The InnerTest class is registered as listener in a service. That Service is running in one thread the calls to readObj() are made from a different thread, hence my question, to ensure consistency of the obj is it enough to make the UpdateObj() method synchronized?
I would suggest using another object as a lock to ensure that the class only blocks when the obj is accessed:
public class Test
{
private final Object lock = new Object();
private Object obj;
public void init()
{
service.registerListener(new InnerTest());
}
public void readObj()
{
synchronized(lock){
// read obj here
}
}
private class InnerTest implements Listener
{
public void updateObj()
{
synchronized(Test.this.lock){
Test.this.obj = new Object();
// change the obj
}
}
}
}
Then use that lock in all methods that need to have consistent access to obj. In your current example the readObj and updateObj methods.
Also as stated in the comments, using synchronized on the method level in your InnerTest class, will not really work as you probably intended. That is, because synchronized methods will use a synchronized block on the this variable. Which just blocks your InnerTest class. But not the outer Test class.
I have a class like this one:
public class IClass{
public void draw(){...}; //is called periodically by the rendering thread
public void foo(){...}; //is called asynchronously from another Thread(it could be an onTouchEvent() method for example)
}
I want the foo() method to wait until the draw method is finished and vice versa. How can I do this in Java?
regards
Make the methods synchronized.
public synchronized void draw() { System.out.println("draw"); }
public synchronized void foo() { System.out.println("foo"); }
Or synchronize on the same object.
private static final Object syncObj = new Object();
public void draw() {
synchronized (syncObj) {
System.out.println("draw");
}
}
public void foo() {
synchronized (syncObj) {
System.out.println("foo");
}
}
Putting synchronized on a method means the thread has to acquire the lock on the object instance before entering that method, so if you have two different methods marked synchronized the threads entering them will be contending for the same lock, and once one thread gets the lock all other threads are shut out of all methods that synchronize on that same lock. So in order for the two methods to run concurrently they would have to use different locks, like this:
public class IClass {
private final Object lockDraw = new Object();
private final Object lockFoo = new Object();
public void draw() {
synchronized(lockDraw) {
//method draw
}
}
public void foo() {
synchronized(lockFoo) {
//method foo
}
}
}
Both methods lock the same monitor. Therefore, you can't simultaneously execute them on the same object from different threads (one of the two methods will block until the other is finished).
Let's say I have a synchronized method on some class:
abstract class Foo {
public synchronized void foo() { // synchronized!
// ...
};
}
and I overrode it without using the synchronized modifier:
class Bar extends Foo {
#Override
public void foo() { // NOT synchronized!
super.foo();
// ...
}
}
I have a couple of specific question regarding this scenario:
Will the overridden method be implicitly synchronized as well?
If not, will the super-call be synchronized?
If there is no super-call, will anything be synchronized?
Is there a way to force an overriding method to use synchronized (I noticed that abstract method definitions or method definitions inside an interface don't allow the synchronized keyword)?
public synchronized void foo() { // synchronized!
// ...
};
Is essentially the same as:
public void foo() {
synchronized (this) { // synchronized!
// ...
}
};
The latter is more explicit, so I would generally suggest using that form. Or better using a lock that is a private field instead of the "outer" object.
So: 1. No. 2. Yes. 3. No. 4. Mark the method final and call a protected method that may be overridden.
public final void foo() {
synchronized (this) {
fooImpl();
}
};
protected void fooImpl() {
// ...
}
As ever, you may well be better off with delegation rather than subclassing.
Failing to use synchronized when overriding a synchronized method has the potential for causing runtime bugs. As a safeguard, there is an Eclipse checker you can turn on to detect this condition.
The default is "ignore". "Warning" is also a valid choice.
which will produce this message:
What would be the behaviour of the following program where static synchronized method and instance synchronized method is trying to access static field of same class in different threads? Will any thread get blocked? Its very confusing.
class MyClass
{
public static int i = 5;
public synchronized void m1()
{
System.out.println(i); //uses static field i of MyClass
//T1 is executing this method
}
public static synchronized void m3()
{
//T2 will be able to call this method on same object lock while it is using
//static field i???
System.out.println(i);//uses static field i of MyClass
}
}
Synchronized instance methods are equivalent of
public void m1() {
synchronized(this) {
...
}
}
(well, they are not exactly the same, but the answer to your question does not suffer from that difference).
Synchronized static methods are synchronized on the class:
public void m2() {
synchronized(MyClass.class) {
...
}
}
As you can see, two block are synchronized on difference objects: m1 is synchronized on the instance it is called on, and m2 is synchronized on the instance of Class<MyClass> which represents your class in JVM. So those two methods can be called without blocking each other.
You are always synchronizing on an object.
Funciton m1 synchronizes on an instance of an object on which it is called.
Function m3 synchronizes on the class itself.
m1 could be written as:
public void m1()
{
synchronized(this) {
System.out.println(i); //uses static field i of MyClass
//T1 is executing this method
}
}
Therefore you are synchronizing on two different objects and these two methods can acces any global variable concurrently.
Your sample code looks good.
Best way to assure synchronization of static variables according to me is. As lock object is not accessible outside your Class. See below.
public class MyClass
{
private static int i = 0;
private static final Object lockObject = new Object();
public void m1() {
synchronized (lockObject ) {
//Use you static var
}
}
public void m3() {
synchronized (lockObject ) {
//Use you static var
}
}
}
The method m1 and m3 can be executed independently.
Because as you already said static synchronized is on the object. Therefore the same as synchronize(MyClass.class).
synchronized are instance wide usable. So it is only blocked for the instances. It would be the same as using:
MyClass myClass = new MyClass();
synchronize (myClass)
{
.....
}
Java does not have any synchronization controls that relate to accessing static fields.
If you make your methods empty, the synchronization will be exactly the same.
Specifically, as long as any thread is executing any synchronized static method in that type, all other threads that call synchronized static methods will wait for them to finish, so that at most one synchronized static method will be executing at once.
What if a synchronized method calls another synchronized method (in another class), which does wait(). Will the lock be released in the first synchronized method as well, although being in another class?
E.g.
public class A {
private B b;
public A(B b) {
this.b = b;
}
public synchronized String a() {
return b.b();
}
}
public class B {
public synchronized String b() {
while (!someCondition) wait();
return "Success!";
}
}
So my question is, will it be possible to enter another synchronized method in A during the time someCondition = false? Or does wait() just make it possible to enter other synchronized methods in B while an attempt to enter another synchronized method in A will fail until a() returns?
No. While invoking a and subsequently b, no other method can enter neither a or b (or any other synchronized method of classes A or B). b.wait() however releases the lock on all synchronized methods on B since
public synchronized String b()
is essentially equivalent to
public String b() {
synchronized(this) {
..
}
}