gsi*_*011 4 java multithreading synchronization
我试图理解线程如何工作,我写了一个简单的例子,我想创建并启动一个新线程,线程,在主线程中显示1到1000的数字,恢复辅助线程,并显示次要线程中的数字从1到1000.当我省略Thread.wait()/ Thread.notify()时,它的行为与预期一致,两个线程一次显示几个数字.当我添加这些函数时,由于某种原因,主线程的数字是第二个而不是第一个打印的.我究竟做错了什么?
public class Main {
public class ExampleThread extends Thread {
public ExampleThread() {
System.out.println("ExampleThread's name is: " + this.getName());
}
@Override
public void run() {
for(int i = 1; i < 1000; i++) {
System.out.println(Thread.currentThread().getName());
System.out.println(i);
}
}
}
public static void main(String[] args) {
new Main().go();
}
public void go() {
Thread t = new ExampleThread();
t.start();
synchronized(t) {
try {
t.wait();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
for(int i = 1; i < 1000; i++) {
System.out.println(Thread.currentThread().getName());
System.out.println(i);
}
synchronized(t) {
t.notify();
}
}
}
Run Code Online (Sandbox Code Playgroud)
Ser*_*mme 11
你误解了如何wait
/ notify
有效.wait
并不能阻止在其上调用它的螺纹; 它阻塞当前线程,直到在同一个对象上调用notify (所以如果你有线程A和B,而在线程A中,称为B.wait(),这将停止线程A而不是线程B - 只要B.notify()未被调用).
因此,在您的具体示例中,如果您希望首先执行主线程,则需要将wait()放在辅助线程中.像这样:
public class Main {
public class ExampleThread extends Thread {
public ExampleThread() {
System.out.println("ExampleThread's name is: " + this.getName());
}
@Override
public void run() {
synchronized (this) {
try {
wait();
} catch (InterruptedException e) {
}
}
for(int i = 1; i < 1000; i++) {
System.out.println(Thread.currentThread().getName());
System.out.println(i);
}
}
}
public static void main(String[] args) {
new Main().go();
}
public void go() {
Thread t = new ExampleThread();
t.start();
for(int i = 1; i < 1000; i++) {
System.out.println(Thread.currentThread().getName());
System.out.println(i);
}
synchronized(t) {
t.notify();
}
}
}
Run Code Online (Sandbox Code Playgroud)
但是,即使此代码可能无法正常工作.在主线程有可能到达wait ()部分之前到达notify()部分的情况下(在你的情况下不太可能,但仍然可能 - 你可以观察它,如果你把Thread.sleep放在在辅助线程的开头),辅助线程永远不会被唤醒.因此,最安全的方法类似于:
public class Main {
public class ExampleThread extends Thread {
public ExampleThread() {
System.out.println("ExampleThread's name is: " + this.getName());
}
@Override
public void run() {
synchronized (this) {
try {
notify();
wait();
} catch (InterruptedException e) {
}
}
for(int i = 1; i < 1000; i++) {
System.out.println(Thread.currentThread().getName());
System.out.println(i);
}
}
}
public static void main(String[] args) {
new Main().go();
}
public void go() {
Thread t = new ExampleThread();
synchronized (t) {
t.start();
try {
t.wait();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
for(int i = 1; i < 1000; i++) {
System.out.println(Thread.currentThread().getName());
System.out.println(i);
}
synchronized(t) {
t.notify();
}
}
}
Run Code Online (Sandbox Code Playgroud)
在此示例中,输出完全是确定性的.这是发生的事情:
t
对象.t
监视器上获得锁定.t
线程.t
监控,辅助线程无法继续,且必须等待(因为它的第一个说法是synchronized (this)
,不是因为它正好是该t
对象-所有的锁,通知并等待可能也被上完成与具有相同结果的2个线程中的任何一个完全无关的对象.t.wait()
部件并暂停其执行,释放t
它同步的监视器.t
监视器的所有权.t.notify()
,唤醒主线程.但主线程还不能继续,因为辅助线程仍然拥有t
监视器的所有权.t.wait()
,暂停其执行并释放t
监视器.t
监视器现在可用.t
监视器的所有权,但立即释放它.t
监视器的所有权.t.notify()
,唤醒辅助线程.辅助线程还不能继续,因为主线程仍然保持t
监视器.t
监视器并终止.t
监视器的所有权,但立即释放它.正如您所看到的,即使在这样一个看似简单的场景中,也会发生很多事情.
归档时间: |
|
查看次数: |
8669 次 |
最近记录: |