Synchronization using object lock in java
I have two threads thread1(printing numbers) & thread2(printing alphabets). My goal is to have the following output via syncronization:
1 a 2 b 3 c 4 d 5 e
class thread1 implements Runnable {
public void run() {
try {
for (int i = 1; i <= 5; i++) {
System.out.println("Is Thread1 holding lock of Testing.class?:"+Thread.holdsLock(Testing.class));
synchronized (Testing.class) {
System.out.println("Is Thread1 holding lock of Testing.class?:"+Thread.holdsLock(Testing.class));
try {
System.out.println(i);
Testing.class.notifyAll();
System.out.println("Thread1:Going to wait");
Testing.class.wait();
System.out.println("Thread1:Resuming from wait");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
System.out.println("Finsihed thread1");
} catch (Exception e) {
System.out.println(e);
}
}
}
class thread2 implements Runnable {
char[] alphabets = { 'a', 'b', 'c', 'd', 'e' };
public void run() {
try {
for (int i = 0; i < 5; i++) {
System.out.println("Is Thread2 holding lock of Testing.class?:"+Thread.holdsLock(Testing.class));
synchronized (Testing.class) {
try {
System.out.println("Is Thread2 holding lock of Testing.class?:"+Thread.holdsLock(Testing.class));
System.out.println("Thread2:Going to wait");
Testing.class.wait();
System.out.println("Thread2:Resuming from wait");
System.out.println(alphabets[i]);
Testing开发者_如何学运维.class.notifyAll();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
} catch (Exception e) {
System.out.println(e);
}
}
}
public class Testing {
public static void main(String[] args) {
Testing w= new Testing();
thread1 t1 = new thread1();
thread2 t2 = new thread2();
Thread th1 = new Thread(t1, "");
Thread th2 = new Thread(t2, "");
try {
th1.start();
th2.start();
} catch (Exception e) {
System.out.println(e);
}
}
}
I am getting the output:
Is Thread1 holding lock of Testing.class?:false
Is Thread1 holding lock of Testing.class?:true
1
Thread1:Going to wait
Is Thread2 holding lock of Testing.class?:false
Is Thread2 holding lock of Testing.class?:true
Thread2:Going to wait
How did thread2 got hold the lock of Testing.class when it was already locked by thread1?. Also, Is there any other elegant way to achieve this sync?. Thanks in advance.
Read a bit more about Java Concurrency.
Calling wait
releases the lock.
When you call the wait()
method, the thread that you call it in is temporarily giving up the lock. So while thread1 is waiting inside the wait()
method, it is not holding the lock, and thread2 can get the lock.
When the wait()
method returns, the thread will hold the lock again.
The API documentation of the wait()
method in class Object
explains this in detail.
The basic problem you have is that you release the synchronized block allowing both threads to go through the loop at the same time. This means either thread can obtain the lock in any order.
AFAIK, The simplest solution is to use a flag.
final int length = 10;
final AtomicBoolean flag = new AtomicBoolean();
new Thread(new Runnable() {
public void run() {
for (int i=1;i<=length;i++) {
while(flag.get());
System.out.print(i+" ");
flag.set(true);
}
}
}).start();
new Thread(new Runnable() {
public void run() {
for (char c='a';c<'a'+length;c++) {
while(!flag.get());
System.out.print(c+" ");
flag.set(false);
}
System.out.println();
}
}).start();
The most elegant way to have this task done in sync is to have one thread. Threads are specificly designed to execute two tasks with as little dependence as possible between them.
BTW
If notifyAll() is called before wait() is called, the notify will be lost. wait() will wait forever.
You create a Testing object you discard (remove it).
You trap InterruptedException which you print and continue as if nothing happened (i.e. remove the nested catch)
This is the complete working code
public class MyClass
{
MyClass mClass;
public void doTest()
{
final int [] a = {1,2,3,4,5,6,7,8,9,10};
final char [] c = {'a','b','c','d','e','f','g','h','i','j'};
mClass = this;
Thread t1 = new Thread(new Runnable(){
public void run()
{
for(int i = 0 ; i<a.length ; i++)
{
synchronized(mClass)
{
System.out.print(a[i]+" ");
mClass.notify();
try{mClass.wait();}catch(Exception e){}
}
}
}
});
t1.start();
Thread t2 = new Thread(new Runnable(){
public void run()
{
for(int i = 0 ; i<c.length ; i++)
{synchronized(mClass)
{
System.out.print(c[i]+" ");
mClass.notify();
try{mClass.wait();}catch(Exception e){}
}
}
}
});
t2.start();
} public static void main(String [] ar) {
new MyClass().doTest();
}
}
public class MyClass { MyClass mClass; boolean isFirstStartedRunning = true; public void doTest() { final int [] a = {1,2,3,4,5,6,7,8,9,10}; final char [] c = {'a','b','c','d','e','f','g','h','i','j'}; mClass = this; Thread t1 = new Thread(new Runnable(){
public void run()
{
isFirstStartedRunning = false;
for(int i = 0 ; i<a.length ; i++)
{
synchronized(mClass)
{
System.out.print(a[i]+" ");
mClass.notify();
if(i==a.length-1)return;
try{mClass.wait();}catch(Exception e){}
}
}
}
});
t1.start();
Thread t2 = new Thread(new Runnable(){
public void run()
{
if(isFirstStartedRunning){
try{mClass.wait();}catch(Exception e){}
}
for(int i = 0 ; i<c.length ; i++)
{
synchronized(mClass)
{
System.out.print(c[i]+" ");
mClass.notify();
if(i==a.length-1)return;
try{mClass.wait();}catch(Exception e){}
}
}
}
});
t2.start();
} public static void main(String [] ar) {
new MyClass().doTest();
}
} check the answer now
精彩评论