Simply put, I'm wondering if this changes the behavior. I'm assuming yes, because calling someMethod() will lock the entire object, instead of just the list object? But I'm still new to this synchronization stuff, so I'd like some more educated feedback.
The before:
public void run() {
int i = 0;
while (!end) {
synchronized (list) {
while (list.size() == i) {
try {
list.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
}
The After:
public void run() {
int i = 0;
while (!end) {
synchronized (list) {
while (list.size() == i) {
someMethod();
}
}
}
}
public synchronized void someMethod() {
try {
list.wait();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
You are correct - the new code has got different semantics, as someMethod() is indeed synchronized on the instance it is being invoked on (and as such, that synchronization is entirely unrelated to the one on list). However, the call to someMethod() will take place while the monitor on list is being held, so a call to run() is "equally thread safe" with respect to list.
On the other hand, you have now introduced the possibility for multiple threads to call someMethod() directly at the same time. You have also introduced a (probably unnecessary) potential for deadlock with other threads due to the extra synchronization on the object itself. I would recommend this instead:
public void someMethod() {
synchronized (list) {
try {
list.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
This method is now safe both for individual use and for being called through run() - note that it is safe to synchronize on an object that you have already synchronized on; the thread won't block itself.
With syncronized you don't really 'lock' an object. You will just make sure that access from everyone who is synchronizing on that specific object is 'regulated' with a lock.
A synchronized method is synchronizing on this.
That means, if you enter a syncronized block on some object list you can call a syncronized method without a problem at first
Some things to be thought about:
This code doesn't produce a deadlock:
public void foo() {
synchronized (this) {
someMethod();
}
}
public synchronized void someMethod() {
// ...
}
because you already have the "lock" on this, but this:
public void foo() {
synchronized (list) {
someMethod();
}
}
public synchronized void someMethod() {
// ...
}
may produce a deadlock with some other thread! You'll have to be really careful if you enter a synchronized section within another synchronized section
Related
I am currently learning the use of monitor in Java, but i do not know how the synchronized methods work.
I understand that while one thread is inside a synchronized method, another thread cannot be inside a synchronized method and that sleep doesn't take off the monitor's own ownership.
So i tried to write a code to test that
import java.util.Random;
public class ex3 extends Thread {
private static int nbA=0;
private static int nbB=0;
public static final Random rand = new Random();
public void run(){
while(true){
System.out.println(nbA+" "+nbB);
try{
Thread.sleep(rand.nextInt(500));
}catch (Exception e ){e.printStackTrace();}
if (rand.nextBoolean()){
try {
A();
} catch (InterruptedException e) {}
}else{
try {
B();
} catch (InterruptedException e) {}
}
}
}
public synchronized void A() throws InterruptedException{
nbA++;
Thread.sleep(rand.nextInt(500));
nbA--;
}
public synchronized void B() throws InterruptedException{
nbB++;
Thread.sleep(rand.nextInt(500));
nbB--;
}
public static void main(String[] argv){
new ex3().start();
new ex3().start();
new ex3().start();
}
}
I believed it was impossible that nbA or nbB be superior to 1 or that nbB and nbA are both >0 but it's happening
What do I misunderstand ?
Sorry for the bad english.
You're synchronizing on different objects: a synchronized non-static method synchronizes on this, so each of the new ex3() instances effectively works like it's not synchronized.
A synchronized instance method is exactly equivalent to this:
public void A() {
synchronized (this) {
// The body.
}
}
Either make the synchronized methods static, or explicitly synchronize on the class (or something other shared object):
public void A() throws InterruptedException{
synchronized (ex3.class) {
nbA++;
Thread.sleep(rand.nextInt(500));
nbA--;
}
}
I understand that while one thread is inside a synchronized method, another thread cannot be inside a synchronized method
Wrong. It cannot be inside a synchronized method synchronized on the same object. It can be inside any other synchronized method, or the same method synchronized on a different object, as here.
and that sleep doesn't take off the monitor's own ownership.
Correct.
NB Per Brinch Hansen doesn't consider Java to have monitors, and he invented them.
Here is my code
class Thread1 extends Thread
{
public synchronized void show()
{
System.out.println("show");
System.out.println(Thread.currentThread().getName());
try
{
Thread.sleep(5000);
}
catch(Exception e)
{
System.out.println(e);
}
}
public synchronized void display()
{
System.out.println("Display");
System.out.println(Thread.currentThread().getName());
}
public static void main(String args[])
{
Thread1 z=new Thread1();
z.set();
}
public void set()
{
Thread1 tr=new Thread1();
Thread1 tr1=new Thread1();
tr.start();
tr1.start();
}
public void run()
{
try
{
show();
display();
}
catch(Exception e)
{
System.out.println(e);
}
}
}
I assume you meant to ask about why show is printed by both threads before either of the thread names are printed.
You are synchronizing your instance methods, so they are implicitly locking on the object on which the method is called. However, you have 2 different Thread1 objects locking on themselves, so neither thread is stopping the other from entering the synchronized methods.
If you intend to have only one Thread execute each of the synchronized methods at a time, then you need to lock on a common object. Use a synchronized block that locks on Thread1.class.
Here is what that looks like for the show method.
public void show()
{
synchronized (Thread1.class)
{
System.out.println("show");
System.out.println(Thread.currentThread().getName());
try
{
Thread.sleep(5000);
}
catch (Exception e)
{
System.out.println(e);
}
}
}
The display method can be modified similarly.
You are instantiating two different objects that have their own state (tr and tr1). They never access the same synchronised block, and thus never block waiting for the other one to finish.
Try moving the show method to another class, instantiate that class and then pass it to tr and tr1 as a constructor parameter, for example.
I have two methods both run by different threads, one of the methods i dont want to run when the other has been called. This is the reason I have chosen to use a lock
#Override
public synchronized void doSomething(int[] params)
{
while (lock.isLocked())
{
// wait for it to become unlocked
}
//lock is released so lets do some stuff
in my other method I have the following implementation
#Override
public void doSomethingElse(int param)
{
lock.lock();
for (int i = 0 ; i < param; i++)
{
//do some stuff
}
lock.unlock();
}
Is the while loop the correct way to say, I want this thread to wait here until the lock is released or is there a better way to implement this
Thanks
The while loop does busy waiting, which is definitely something you don't want to do.
Calling lock.lock(); will block until the lock is released, so it's the proper way to do it, just like you're doing in your other method.
You also don't need for the first method to be synchronized, and the lock should always be released in a finally clause.
You need something like this:
private void method1()
{
lock.lock();
try {
...
} finally {
lock.unlock();
}
}
private void method2()
{
lock.lock();
try {
...
} finally {
lock.unlock();
}
}
Don't forgeet to use try {} finally{} or you could end up with deadlock.
Both wrong, the standard practice is to unlock in the finally clause. Otherwise the application will stall if exception is thrown from inside the code where the lock applies:
public void doSomethingElse(int param) throws Exception {
lock.lock();
try {
//do some stuff that may throw exceptions
} finally {
lock.unlock();
}
}
Code snippet:
class Counter implements Runnable {
Object s = new Object();
#Override
public void run() {
try {
synchronized (s) {
s.wait(10000);
}
} catch (InterruptedException e) {
e.printStackTrace();
}
//...do Something
}
public void stopCounter() {
synchronized (s) {
s.notifyAll();
}
}
}
Irrespective of whether i call stopCounter or not, the ...do Something code always executes only after the wait interval. Even after notify it still waits for 10 secs.
I cannot tell from your example what you are trying to achieve. If it is to try and replace some sort of polling then consider the BlockingQueue interface that was released in Java 5. Since that has appeared I have had no need for wait/notify. It's a lot more simple to use and java behind the scenes does the equivalent of the wait/notify for you.
It depends of the way you use it. I have just tried it by adding a main method and running it and it seems like the wait / notify mechanism is working fine, not the way you described it. Please try it yourself:
public static void main(String[] args) {
Counter c = new Counter();
new Thread(c).start();
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
c.stopCounter();
}
My guess is that you call the run and stopCounter methods on different instances of your Counter class. They therefore use different monitors (your s = new Object()) and the call to stop won't notify the other Counter.
For example, this would behave similarly to what you describe (unless you get a spurious wakeup):
public static void main(String[] args) throws InterruptedException {
Counter c = new Counter();
new Thread(c).start();
Thread.sleep(200);
new Counter().stopCounter();
}
static class Counter implements Runnable {
Object s = new Object();
#Override
public void run() {
try {
System.out.println("in");
synchronized (s) {
s.wait(10000);
}
System.out.println("out");
} catch (InterruptedException e) {
e.printStackTrace();
}
//...do Something
}
public void stopCounter() {
synchronized (s) {
s.notifyAll();
}
System.out.println("notified");
}
}
public class Common {
public synchronized void synchronizedMethod1() {
System.out.println("synchronizedMethod1 called");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("synchronizedMethod1 done");
}
public void method1() {
System.out.println("Method 1 called");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("Method 1 done");
}
}
public class MyThread extends Thread {
private int id = 0;
private Common common;
public MyThread(String name, int no, Common object) {
super(name);
common = object;
id = no;
}
public void run() {
System.out.println("Running Thread" + this.getName());
try {
if (id == 0) {
common.synchronizedMethod1();
} else {
common.method1();
}
} catch (Exception e) {
e.printStackTrace();
}
}
public static void main(String[] args) {
Common c = new Common();
MyThread t1 = new MyThread("MyThread-1", 0, c);
MyThread t2 = new MyThread("MyThread-2", 1, c);
t1.start();
t2.start();
}
}
Output:
Running ThreadMyThread-1
synchronizedMethod1 called
Running ThreadMyThread-2
Method 1 called
synchronizedMethod1 done
Method 1 done
I would like to find a way to prevent method1() from running when i called synchronizedMethod1. Unless I'm mistaken all methods are called and Java compiles them during and before runtime regardless if it's synchronized or not.
Should i have used a Lock object instead and/or not also make method1() a synchronized method?
I would like to find a way to prevent method1() from running when i called synchronizedMethod1
The easiest way to do this is to make method1() also be synchronized. This will mean that both methods will cause a lock on the instance of Common that they are calling. Only one thread will be able to either be calling synchronizedMethod1() or method1().
Unless I'm mistaken all methods are called and Java compiles them during and before runtime regardless if it's synchronized or not.
I don't understand this question. You really should not have to worry about the compilation or optimization phase of the JVM.
Should i have used a Lock object instead?
Usually making a method synchronized is considered not as good as using a private final lock object. Lock objects just allow you to be more fine grained in your locks. For example, with method locking, log messages and other statements that do not need protection will be synchronized as well. But if the goal is to lock the entire method then synchronizing the methods is fine.
If you want method1 and synchronizedMethod1 to be mutually exclusive then you need to guard them with the same lock. Whether this is using a Lock or simply calling synchronize on the same Object instance, the outcome is roughly the same.
On the off chance you want multiple threads to be allowed to execute method1 but not when synchronizedMethod1 is being invoked, you need a ReadWriteLock to accomplish that.
public class Common {
ReadWriteLock rwLock = new ReentrantReadWriteLock();
public void synchronizedMethod1() {
rwLock.writeLock().lock();
try {
System.out.println("synchronizedMethod1 called");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("synchronizedMethod1 done");
} finally {
rwLock.writeLock().unlock();
}
}
public void method1() {
rwLock.readLock().lock();
try {
System.out.println("Method 1 called");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("Method 1 done");
} finally {
rwLock.readLock().unlock();
}
}
}