java中的多线程(两个线程广泛使用notify()和wait()
当我尝试运行以下程序时,在这段代码中对notify()的第一次调用中有一个非法MonitorStateException:java中的多线程(两个线程广泛使用notify()和wait(),java,multithreading,notify,Java,Multithreading,Notify,当我尝试运行以下程序时,在这段代码中对notify()的第一次调用中有一个非法MonitorStateException: synchronized (c) { try { notify(); .... 这让我有点发火:当对象(c)已经在同步块中,并且检查相同的锁时,代码怎么可能没有锁呢 请不要介意过度使用notify()和wait(),看起来有些奇怪。我知道有不同的(更有效的)实现可以执行相同的任务,但现在我正在试图弄清楚为什么这个特定的实现不起作用
synchronized (c) {
try {
notify();
....
这让我有点发火:当对象(c)已经在同步块中,并且检查相同的锁时,代码怎么可能没有锁呢
请不要介意过度使用notify()和wait(),看起来有些奇怪。我知道有不同的(更有效的)实现可以执行相同的任务,但现在我正在试图弄清楚为什么这个特定的实现不起作用
完整代码如下:
class J implements Runnable {
public static void main(String[] x) {
Calc calc = new Calc();
J j = new J(calc);
Thread t1 = new Thread(j, "one");
Thread tCalc = new Thread(calc, "Calc");
tCalc.start();
t1.start();
}
Calc c;
public J(Calc c) {
this.c = c;
}
public void run() {
synchronized (c) {
try {
notify();
c.wait();
} catch (InterruptedException e) {
}
System.out.println(Thread.currentThread().getName() + ": x = "
+ c.getX());
notify();
}
}
}
class Calc implements Runnable {
private int x;
public int getX() {
return x;
}
public void run() {
synchronized (this) {
for (int x = 1; x <= 11111; x *= (x + x)) {
this.x += x;
try {
notify();
this.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
notify();
}
}
}
J类实现可运行{
公共静态void main(字符串[]x){
Calc Calc=新的Calc();
J=新J(计算);
螺纹t1=新螺纹(j,“一”);
线程tCalc=新线程(计算,“计算”);
tCalc.start();
t1.start();
}
钙;
公共J(计算){
这个.c=c;
}
公开募捐{
已同步(c){
试一试{
通知();
c、 等待();
}捕捉(中断异常e){
}
System.out.println(Thread.currentThread().getName()+“:x=”
+c.getX());
通知();
}
}
}
类Calc实现了Runnable{
私人INTX;
公共int getX(){
返回x;
}
公开募捐{
已同步(此){
对于(intx=1;x,您正试图通知一个线程,该线程正在等待一个当前未持有的锁。
错误是正确的。您在对象c上有一个锁,然后通知其他线程当前对象上的锁。您试图通知一个线程,该线程正在等待一个当前未持有的锁。
synchronized (c) {
try {
notify();
....
该错误是正确的。您在对象c上有一个锁,然后通知其他线程当前对象上的锁
synchronized (c) {
try {
notify();
....
您正在锁定对象c
,但正在通知对象此
。一个好的做法是始终指定将来显式打开的对象wait()
或notify()
。您应该执行以下操作:
synchronized (c) {
try {
c.notify();
....
或:
看起来你实际上是想处理两个锁。如果是这样的话,你应该做如下的事情
synchronized (c) {
try {
synchronized (this) {
this.notify();
}
c.wait();
务必确保始终先锁定c
,然后再锁定此
,否则会死锁
您正在锁定对象c
,但正在通知对象此
。一个好的做法是始终指定将来显式打开的对象wait()
或notify()
。您应该执行以下操作:
synchronized (c) {
try {
c.notify();
....
或:
看起来你实际上是想处理两个锁。如果是这样的话,你应该做如下的事情
synchronized (c) {
try {
synchronized (this) {
this.notify();
}
c.wait();
务必确保始终先锁定c
,然后再锁定此
,否则会死锁。执行以下操作的方法很复杂
ExecutorService printer = Executors.newSingleThreadExecutor();
int x2 = 0;
for (int x = 1; x <= 11111; x *= (x + x)) {
x2 += x;
final int x3 = x2;
printer.submit(new Runnable() {
@Override
public void run() {
System.out.println(Thread.currentThread().getName() + ": x = " + x3);
}
});
}
printer.shutdown();
ExecutorService printer=Executors.newSingleThreadExecutor();
int x2=0;
对于(intx=1;x来说,您所拥有的是执行以下操作的复杂方式
ExecutorService printer = Executors.newSingleThreadExecutor();
int x2 = 0;
for (int x = 1; x <= 11111; x *= (x + x)) {
x2 += x;
final int x3 = x2;
printer.submit(new Runnable() {
@Override
public void run() {
System.out.println(Thread.currentThread().getName() + ": x = " + x3);
}
});
}
printer.shutdown();
ExecutorService printer=Executors.newSingleThreadExecutor();
int x2=0;
对于(int x=1;x Correct-具体地说,notify();
表示this.notify();
,而不是c.notify();
。您需要synchronize(this)
调用notify();
,就我所知(不知何故我知道这是不对的,但不完全确定为什么)在类J中同步(c)并同步(this)在类Calc中,本质上是相同的对象锁-因为类J有一个实例字段Calc。在主类Calc中,很明显只有一个实例,这是在类J被构造时传递的。是的,它是相同的对象,但这不是问题。问题是在这段代码中:synchronized(c){try{notify();…您拥有c的锁,然后调用j.notify(),这将导致抛出异常Ep,多亏格雷在下面的评论,我已经解决了所有问题。我的问题是,我读的书强调了notify()的使用,而不是specificularObject.notify()(因为它关注的是同步方法而不是块)这些细微差别对我来说并不完全清楚。谢谢你的澄清!正确-具体地说,notify();
的意思是this.notify();
,而不是c.notify();
。在我看来,你需要同步(this)
才能调用notify();
(不知何故,我知道这是不对的,但不完全确定为什么)在类J中同步(c)和同步(这个)在类Calc中,本质上是相同的对象锁-因为类J有一个实例字段Calc。在主类Calc中,很明显只有一个实例,这是在类J被构造时传递的。是的,它是相同的对象,但这不是问题。问题是在这段代码中:synchronized(c){try{notify();…您拥有c的锁,然后调用j.notify(),这将导致抛出异常Ep,多亏格雷在下面的评论,我已经解决了所有问题。我的问题是,我读的书强调了notify()的使用,而不是specificularObject.notify()(因为它关注的是同步方法而不是块)这些细微差别对我来说并不完全清楚。谢谢你的澄清!谢谢格雷,现在在你的第一行评论之后,我看清楚了。我错误地认为,当你输入一个同步块,并将一个指定的对象作为锁时,只要调用notify(),它就会自动得到支持