Reputation: 231
I just started working with notify, synchronized and wait, and it almost works, but only when I let the second Thread sleep() for 1 ms. You can see my console output at the end.
My main:
public static void main(String[] args) {
InfoPaket paket = new InfoPaket();
TestThread testThread = new TestThread(paket);
TestThread2 testThread2 = new TestThread2(paket);
}
My "Lock" Class
public class InfoPaket {
String info;
char infoDataSign;
boolean newInfo = false;
public synchronized boolean isNew(){
if (!newInfo){
try {
System.out.println("waiting");
wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
return newInfo;
}
public synchronized String getInfo() {
newInfo = false;
return info;
}
public synchronized void setInfo(String info) {this.info = info;
newInfo = true;
notify();
}
My two test Thread
1.
public class TestThread implements Runnable {
InfoPaket info;
int i = 0;
public TestThread(InfoPaket info) {
this.info = info;
new Thread(this,"TestThread").start();
}
public void run() {
while(true){
i++;
getInfo();
}
}
void getInfo(){
info.isNew();
System.out.println("he got it... " + info.getInfo() + " " + i);
}
2.
public class TestThread2 implements Runnable{
InfoPaket info;
Thread t;
int i = 0;
public TestThread2(InfoPaket info) {
this.info = info;
t = new Thread(this,"TestThread");
t.start();
}
public void run() {
while(i < 500000){
i++;
setInfo();
}
}
void setInfo(){
info.setInfo("lelaoao");
System.out.println("here " + i);
try {
t.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
Here my results which are very clear and nice (except for the start):
waiting
he got it... lelaoao 1
waiting
here 1
here 2
he got it... lelaoao 2
waiting
here 3
he got it... lelaoao 3
waiting
here 4
he got it... lelaoao 4
waiting
here 5
he got it... lelaoao 5
waiting
here 6
he got it... lelaoao 6
And so on..
But putting the 2. thread everytime asleep slows down the program, but without it I get something strange that I can't explain to myself:
waiting
here 1
he got it... lelaoao 1
he got it... lelaoao 2
waiting
here 2
here 3
he got it... lelaoao 3
he got it... lelaoao 4
waiting
here 4
here 5
here 6
here 7
here 8
here 9
here 10
he got it... lelaoao 5
he got it... lelaoao 6
waiting
Upvotes: 1
Views: 92
Reputation: 14658
You code is working as expected (as coded), except - 1) You have some bad code 2) You may have misunderstood the concept.
Let me first start by saying what your code is doing:
InfoPaket
which is shared among your 2 thread and hold info about packet, and keeps track whether new info is received or not.TestThread
which will check if new info is received or not, if new info is not recieved then it will wait and once new info is received then you will print the info (which is always "lelaoao") along with your loop counter, like this he got it... lelaoao 23
TestThread2
which will set the info and notify the waiting thread and then print the loop counter of this thread like this - "here " + i
.Now, most important thing for your understand is that thread scheduling is unexpected and depends on underlying OS thread scheduling mechanism as well as JVM implementation, so you cannot expect that if thread 2 has set info then then certainly thread 1 will execute, you can try to enforce it putting Thread.sleep(1)
or Thread.yeild()
, please note that Thread.yeild()
is not portable and it is good that you are not using it and should not be use it, instead of it you should use Thread.sleep(1)
Now let come to bad code and some important concepts:
TestThread2
because you can directly do Thread.sleep(1);
which will cause current thread to sleep.System.out.println("he got it... " + info + " " + i);
and System.out.println("here " + i);
from your main thread, however you should print these from synchronized block to ensure that there is no interleaving, because in absence of synchronization interleaving could occur and you could see he got it... lelaoao 3
before here 3
which is logically wrong.Now, below is the fixed code which will consistent produce correct result (considering your are giving thread 1 chance to run once thread 2 has set info), output is also placed in the end.
InfoPaket.java
public class InfoPaket {
String info;
char infoDataSign;
boolean newInfo = false;
public synchronized boolean isNew() {
if (!newInfo) {
try {
System.out.println("waiting");
wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
return newInfo;
}
public synchronized void getInfo(int i) {
newInfo = false;
System.out.println("he got it... " + info + " " + i);
}
public synchronized void setInfo(String info, int i) {
this.info = info;
newInfo = true;
System.out.println("here " + i);
notify();
}
public static void main(String[] args) {
InfoPaket paket = new InfoPaket();
TestThread testThread = new TestThread(paket);
TestThread2 testThread2 = new TestThread2(paket);
new Thread(testThread, "testThread").start();
new Thread(testThread2, "testThread2").start();
}
}
TestThread.java
public class TestThread implements Runnable {
InfoPaket info;
int i = 0;
public TestThread(InfoPaket info) {
this.info = info;
}
public void run() {
while (true) {
i++;
getInfo(i);
}
}
void getInfo(int i2){
info.isNew();
info.getInfo(i2);
}
}
TestThread2.java
public class TestThread2 implements Runnable {
InfoPaket info;
int i = 0;
public TestThread2(InfoPaket info) {
this.info = info;
}
public void run() {
while (i < 500000) {
i++;
setInfo(i);
}
}
void setInfo(int i2) {
info.setInfo("lelaoao", i2);
try {
Thread.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
Output:
waiting
here 1
he got it... lelaoao 1
waiting
here 2
he got it... lelaoao 2
waiting
here 3
he got it... lelaoao 3
waiting
here 4
he got it... lelaoao 4
waiting
here 5
he got it... lelaoao 5
waiting
here 6
he got it... lelaoao 6
waiting
here 7
he got it... lelaoao 7
waiting
here 8
he got it... lelaoao 8
waiting
here 9
he got it... lelaoao 9
waiting
here 10
he got it... lelaoao 10
waiting
here 11
he got it... lelaoao 11
waiting
here 12
he got it... lelaoao 12
waiting
here 13
he got it... lelaoao 13
waiting
here 14
he got it... lelaoao 14
waiting
here 15
he got it... lelaoao 15
waiting
here 16
he got it... lelaoao 16
waiting
here 17
he got it... lelaoao 17
waiting
here 18
he got it... lelaoao 18
waiting
here 19
he got it... lelaoao 19
waiting
here 20
he got it... lelaoao 20
waiting
here 21
he got it... lelaoao 21
waiting
here 22
he got it... lelaoao 22
waiting
here 23
he got it... lelaoao 23
waiting
here 24
he got it... lelaoao 24
waiting
here 25
he got it... lelaoao 25
waiting
here 26
he got it... lelaoao 26
waiting
here 27
he got it... lelaoao 27
waiting
here 28
he got it... lelaoao 28
waiting
here 29
he got it... lelaoao 29
waiting
here 30
he got it... lelaoao 30
waiting
here 31
he got it... lelaoao 31
I think you might be missing some concept so you are thinking output to be crazy.
Thread.yield()
and Thread.sleep()
. With that note, if you don't use Thread.sleep(1)
then you just can't expect output to be consistent, as I have shown below.Thread.sleep
then it doesn't release the lock, if that thread is acquiring some lock.notify();
then you can't expect the waiting thread to be "runnable" immediately and the thread which is acquiring the lock will not release immediately release the lock as soon as notify();
is called, lock will be released only once that synchronized block/method is finished.Thread.sleep(1)
in your 2nd thread then you can't expect the consistent output, and reasons I have explained above.OP's comment:
Do you know any a more efficent way of transmitting data from on thread to an other one?
Either you have "shared memory" or "message passing"; shared memory is what we are doing in this case, and if you want to go for message passing then you can go for Java API like blocking queue (https://docs.oracle.com/javase/7/docs/api/java/util/concurrent/BlockingQueue.html) implementation, but that's becomes all together different story.
Upvotes: 1