How to call same instance methods in different orders

L

lonelyplanet999

Hi,

I'm studying 310-035 exam and I use "Java 2 - Sun Certified Programmer
& Developer for Java 2 (310-035) by Kathy Sierra, Bert Bates" as my
study guide.

In chapter 9 of the book there is segment of code discussing about
deadlock:

class DeadlockRisk {
private static class Resource {
public int value;
}
private Resource resourceA = new Resource();
private Resource resourceB = new Resource();
public int read() {
synchronized(resourceA) {
synchronized(resourceB) {
return resourceB.value + resourceA.value;
}
}
}

public void write(int a, int b) {
synchronized(resourceB) {
synchronized(resourceA) {
resourceA.value = a;
resourceB.value = b;
}
}
}
}

I intend to implement main() method as below:

public class P526 extends Thread {
DeadlockRisk dl;
public void register(DeadlockRisk d) {
this.dl = d;
}
public void run() {

}
public static void main(String[] args) {
DeadlockRisk dlock = new DeadlockRisk();
P526 a = new P526();
P526 b = new P526();
a.dl = dlock;
b.dl = dlock;
a.start();
b.start();
}
}

However, there is only one run() method to override, I don't know how
to control the 2 threads a & b such that one of them start calling
read() method while the other start calling write() method first.
Could anyone suggest a feasible solution for this problem ?

Tks :)
 
J

John C. Bollinger

lonelyplanet999 wrote:

[...]
public class P526 extends Thread {
DeadlockRisk dl;
public void register(DeadlockRisk d) {
this.dl = d;
}
public void run() {

}
public static void main(String[] args) {
DeadlockRisk dlock = new DeadlockRisk();
P526 a = new P526();
P526 b = new P526();
a.dl = dlock;
b.dl = dlock;
a.start();
b.start();
}
}

However, there is only one run() method to override, I don't know how
to control the 2 threads a & b such that one of them start calling
read() method while the other start calling write() method first.
Could anyone suggest a feasible solution for this problem ?

(1) Use different classes.
(2) Add a configuration flag to the class that tells it which order to use


John Bollinger
(e-mail address removed)
 
L

lonelyplanet999

John C. Bollinger said:
lonelyplanet999 wrote:

[...]
public class P526 extends Thread {
DeadlockRisk dl;
public void register(DeadlockRisk d) {
this.dl = d;
}
public void run() {

}
public static void main(String[] args) {
DeadlockRisk dlock = new DeadlockRisk();
P526 a = new P526();
P526 b = new P526();
a.dl = dlock;
b.dl = dlock;
a.start();
b.start();
}
}

However, there is only one run() method to override, I don't know how
to control the 2 threads a & b such that one of them start calling
read() method while the other start calling write() method first.
Could anyone suggest a feasible solution for this problem ?

(1) Use different classes.

You mean I define resourceA & resourceB as members of 2 different
classes ?
(2) Add a configuration flag to the class that tells it which order to use

But the methods read() & write() attempt to access resourceA &
resourceB. If resourceA & resourceB were placed in different classes,
how can I changed to methods to access the same variable ?
 
L

lonelyplanet999

John C. Bollinger said:
lonelyplanet999 wrote:

[...]
public class P526 extends Thread {
DeadlockRisk dl;
public void register(DeadlockRisk d) {
this.dl = d;
}
public void run() {

}
public static void main(String[] args) {
DeadlockRisk dlock = new DeadlockRisk();
P526 a = new P526();
P526 b = new P526();
a.dl = dlock;
b.dl = dlock;
a.start();
b.start();
}
}

However, there is only one run() method to override, I don't know how
to control the 2 threads a & b such that one of them start calling
read() method while the other start calling write() method first.
Could anyone suggest a feasible solution for this problem ?

(1) Use different classes.

You mean I define resourceA & resourceB as members of 2 different
classes ?
(2) Add a configuration flag to the class that tells it which order to use

But the final processing need to pass through run() method which
didn't allow parameters, otherwise it's no longer a thread's method.
 
A

Amol

But the final processing need to pass through run() method which
didn't allow parameters, otherwise it's no longer a thread's method.
pass the flag in the constructor (e.g. true for A and false for B).
Use this in the run method to decide whether you want to read or
write.
 
J

John C. Bollinger

lonelyplanet999 said:
John C. Bollinger said:
lonelyplanet999 wrote:

[...]

public class P526 extends Thread {
DeadlockRisk dl;
public void register(DeadlockRisk d) {
this.dl = d;
}
public void run() {

}
public static void main(String[] args) {
DeadlockRisk dlock = new DeadlockRisk();
P526 a = new P526();
P526 b = new P526();
a.dl = dlock;
b.dl = dlock;
a.start();
b.start();
}
}

However, there is only one run() method to override, I don't know how
to control the 2 threads a & b such that one of them start calling
read() method while the other start calling write() method first.
Could anyone suggest a feasible solution for this problem ?

(1) Use different classes.


You mean I define resourceA & resourceB as members of 2 different
classes ?

Basically, yes. Then you have two run methods you can configure. There
are various ways of doing it, but the bottom line is that to have two
different run() methods, you must have two different classes.
But the methods read() & write() attempt to access resourceA &
resourceB. If resourceA & resourceB were placed in different classes,
how can I changed to methods to access the same variable ?

That is an alternative solution, not a second step.


John Bollinger
(e-mail address removed)
 
J

John C. Bollinger

lonelyplanet999 said:
But the final processing need to pass through run() method which
didn't allow parameters, otherwise it's no longer a thread's method.

"[...] to the _class_ [...]" (emphasis mine). Implicit was that the
flag be an instance variable, as opposed to a static variable. Each
instance of the class then has its own copy of the flag, and the run()
method can refer to for determining the order of methods to invoke. The
flag can be set in the constructor or however else you like, so long as
it is set before you start the threads.


John Bollinger
(e-mail address removed)
 
L

lonelyplanet999

John C. Bollinger said:
lonelyplanet999 wrote:

Bingo! I modified the code as below:
1. Class DeadlockRisk basically no change in structure.
2. Use two classes of threads instead of one. This avoid more complex
flag settings to distinguish whether read() or write() should be
called first.
3. To increase the possibility of deadlock, I added sleep interval in
both read() & write() just after the first synchronized call.
4. I compiled & ran the program. It output

a starts read()
b starts write()

Then console stopped displaying more and program didn't continue.
Without the sleep call, both threads ran to completion as if nothing
happened.

^o^

====================
class DeadlockRisk {
private static class Resource {
public int value;
}
private Resource resourceA = new Resource();
private Resource resourceB = new Resource();
public int read() {
synchronized(resourceA) {
try {
Thread.sleep(1000);
} catch(InterruptedException e) {}
synchronized(resourceB) {
System.out.println(Thread.currentThread().getName()+".read()
returns "+(resourceB.value+resourceA.value));
return resourceB.value + resourceA.value;
}
}
}

public void write(int a, int b) {
synchronized(resourceB) {
try {
Thread.sleep(1000);
} catch(InterruptedException e) {}
synchronized(resourceA) {
resourceA.value = a;
resourceB.value = b;
System.out.println(Thread.currentThread().getName()+" set
resourceA="+a+" resourceB="+b);
}
}
}

}

class plockA extends Thread {
private String name;
private DeadlockRisk da;
plockA(String n, DeadlockRisk d) {
name = n;
da = d;
}
public void run() {
System.out.println(name+" starts read()");
da.read();
System.out.println(name+" starts write()");
da.write(1,1);
}
}

class plockB extends Thread {
private String name;
private DeadlockRisk db;
plockB(String n, DeadlockRisk d) {
name = n;
db = d;
}
public void run() {
System.out.println(name+" starts write()");
db.write(2,2);
System.out.println(name+" starts read()");
db.read();
}
}

public class P526 extends Thread {
public static void main(String[] args) {
DeadlockRisk dlock = new DeadlockRisk();
plockA a = new plockA("a",dlock);
plockB b = new plockB("b",dlock);
a.start();
b.start();
}
}


John C. Bollinger said:
lonelyplanet999 wrote:

[...]


public class P526 extends Thread {
DeadlockRisk dl;
public void register(DeadlockRisk d) {
this.dl = d;
}
public void run() {

}
public static void main(String[] args) {
DeadlockRisk dlock = new DeadlockRisk();
P526 a = new P526();
P526 b = new P526();
a.dl = dlock;
b.dl = dlock;
a.start();
b.start();
}
}

However, there is only one run() method to override, I don't know how
to control the 2 threads a & b such that one of them start calling
read() method while the other start calling write() method first.
Could anyone suggest a feasible solution for this problem ?

(1) Use different classes.


You mean I define resourceA & resourceB as members of 2 different
classes ?

Basically, yes. Then you have two run methods you can configure. There
are various ways of doing it, but the bottom line is that to have two
different run() methods, you must have two different classes.
But the methods read() & write() attempt to access resourceA &
resourceB. If resourceA & resourceB were placed in different classes,
how can I changed to methods to access the same variable ?

That is an alternative solution, not a second step.


John Bollinger
(e-mail address removed)
 
J

jerry

lonelyplanet999 said:
John C. Bollinger said:
lonelyplanet999 wrote:


Bingo! I modified the code as below:
1. Class DeadlockRisk basically no change in structure.
2. Use two classes of threads instead of one. This avoid more complex
flag settings to distinguish whether read() or write() should be
called first.
3. To increase the possibility of deadlock, I added sleep interval in
both read() & write() just after the first synchronized call.
4. I compiled & ran the program. It output

a starts read()
b starts write()

Then console stopped displaying more and program didn't continue.
Without the sleep call, both threads ran to completion as if nothing
happened.

^o^

====================
class DeadlockRisk {
private static class Resource {
public int value;
}
private Resource resourceA = new Resource();
private Resource resourceB = new Resource();
public int read() {
synchronized(resourceA) {
try {
Thread.sleep(1000);
} catch(InterruptedException e) {}
synchronized(resourceB) {
System.out.println(Thread.currentThread().getName()+".read()
returns "+(resourceB.value+resourceA.value));
return resourceB.value + resourceA.value;
}
}
}

public void write(int a, int b) {
synchronized(resourceB) {
try {
Thread.sleep(1000);
} catch(InterruptedException e) {}
synchronized(resourceA) {
resourceA.value = a;
resourceB.value = b;
System.out.println(Thread.currentThread().getName()+" set
resourceA="+a+" resourceB="+b);
}
}
}

}

class plockA extends Thread {
private String name;
private DeadlockRisk da;
plockA(String n, DeadlockRisk d) {
name = n;
da = d;
}
public void run() {
System.out.println(name+" starts read()");
da.read();
System.out.println(name+" starts write()");
da.write(1,1);
}
}

class plockB extends Thread {
private String name;
private DeadlockRisk db;
plockB(String n, DeadlockRisk d) {
name = n;
db = d;
}
public void run() {
System.out.println(name+" starts write()");
db.write(2,2);
System.out.println(name+" starts read()");
db.read();
}
}

public class P526 extends Thread {
public static void main(String[] args) {
DeadlockRisk dlock = new DeadlockRisk();
plockA a = new plockA("a",dlock);
plockB b = new plockB("b",dlock);
a.start();
b.start();
}
}


<snip...>

Is what are you trying to do something like that?

change thw plockA to :



class plockA extends Thread {

private String name;
private DeadlockRisk da;
private boolean flag = false; //Added

plockA(String n, DeadlockRisk d) {
name = n;
da = d;
}
public void run() {

while(true) { //Added
if(flag == true){ //Added
System.out.println(name+" starts read()");
da.read();
flag = false; //Added
}else if (flag == false) { //Added
System.out.println(name+" starts write()");
da.write(1,1);
flag = true; //Added
}
}
}
}

and remove from the main the plockB:

public class P526 extends Thread {
public static void main(String[] args) {
DeadlockRisk dlock = new DeadlockRisk();
plockA a = new plockA("a",dlock);
a.start();
}
}

The Output is something like that:

a starts write()
Thread-0 set resourceA=1 resourceB=1
a starts read()
Thread-0.read()returns 2
a starts write()
Thread-0 set resourceA=1 resourceB=1
a starts read()
Thread-0.read()returns 2
.....
.....

You can also pass the flag variable to the constructor so you can start
the read or write method first.

if you want two threads doing that, you should create a static variable
like flag in the DeadlockRisk class
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,995
Messages
2,570,230
Members
46,817
Latest member
DicWeils

Latest Threads

Top