我刚开始使用notify,synchronized和wait,它几乎可以工作,但只有当我让第二个Thread sleep()1 ms时才会这样。你可以在最后看到我的控制台输出。
我的主要人物:
public static void main(String[] args) {
InfoPaket paket = new InfoPaket();
TestThread testThread = new TestThread(paket);
TestThread2 testThread2 = new TestThread2(paket);
}
我的“锁定”类
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();
}
我的两个测试线程
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();
}
}
这里我的结果非常清晰明确(除了开头):
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
等等..
但是每次睡着时都会把2个线程放慢速度, 但没有它,我会发现一些我无法向自己解释的奇怪的事情:
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
答案 0 :(得分:1)
您的代码按预期工作(如编码),除了 - 1)您有一些不良代码2)您可能误解了这个概念。
首先让我先谈谈你的代码在做什么:
InfoPaket
并保存有关数据包的信息,并跟踪是否收到新信息。TestThread
将检查是否收到新信息,如果没有收到新信息,那么它将等待,一旦收到新信息,您将打印信息(始终是“lelaoao” “)以及你的循环计数器,如he got it... lelaoao 23
TestThread2
将设置信息并通知等待的线程,然后像这样打印这个线程的循环计数器 - "here " + i
。现在,您理解的最重要的事情是线程调度是意外的并且依赖于底层的OS线程调度机制以及JVM实现,因此您不能指望如果线程2设置了信息然后肯定线程1将执行,您可以尝试强制执行Thread.sleep(1)
或Thread.yeild()
,请注意Thread.yeild()
不可移植,这对您有好处没有使用它,不应该使用它,而不是它,你应该使用Thread.sleep(1)
现在让我们来看看糟糕的代码和一些重要的概念:
TestThread2
中引用当前线程,因为您可以直接执行Thread.sleep(1);
,这将导致当前线程进入休眠状态。System.out.println("he got it... " + info + " " + i);
和System.out.println("here " + i);
,但是您应该从synchronized块打印这些以确保没有交错,因为在没有同步交错时可能会发生< / strong>,您可以在he got it... lelaoao 3
之前看到here 3
,这在逻辑上是错误的。现在,下面是固定代码,它将一致地产生正确的结果(考虑到你的线程1有机会在线程2设置信息后运行),输出也放在最后。< / p>
<强> 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();
}
}
}
<强>输出:强>
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
我认为你可能会错过一些概念,所以你认为输出是疯狂的。
Thread.yield()
和Thread.sleep()
。有了这个说明,如果你不使用Thread.sleep(1)
那么你就不能指望输出是一致的,正如我在下面所示。Thread.sleep
时,如果该线程正在获取锁定,则不会释放锁定。notify();
,你就不能指望等待线程立即“可运行”,并且获取锁定的线程将不会立即释放锁定notify();
是调用后,只有在同步块/方法完成后才会释放锁。Thread.sleep(1)
,那么你就不能指望一致的输出,以及我上面解释的原因。您是否知道从中传输数据的更有效方法? 线程到另一个?
您有“共享内存”或“消息传递”;共享内存就是我们在这种情况下正在做的事情,如果你想进行消息传递,那么你可以使用像阻塞队列(https://docs.oracle.com/javase/7/docs/api/java/util/concurrent/BlockingQueue.html)实现这样的Java API,但这就变成了不同的故事。