public class Main {
public static void main(String[] agrs) {
T1 t1 = new T1();
T2 t2 = new T2();

t1.start();
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
t2.start();
}
public static Integer lockObj = new Integer(0);
}class T1 extends Thread {
public void run() {
synchronized(Main.lockObj) {
for (int i= 65; i< 70; ++i) {
System.out.print(String.format("%d = ", i));
try {
Main.lockObj.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
}class T2 extends Thread {
public void run() {
for (char i= 'A'; i< 'F'; ++i) {
synchronized(Main.lockObj) {
System.out.println(i);
Main.lockObj.notify();
}
try {
sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
上面的代码就是两个线程,如果T2不sleep的话,就不能交替执行。程序本意是T1打印一行,然后wait释放锁,T2就能获得锁,T2获得锁之后打印一行,然后notify把锁还给T1,这就出问题了,T2调notify之后并不是正在wait的T1的重新获得,因为此时T2也想获得锁,有可能又被T2获得了。所以,顺序就乱了,如果在T2里面加个延时,就对了,T2在notify之后,延时100毫秒,才能保证被T1抢过来。

解决方案 »

  1.   

    LZ改成这样就可以了吧,虽然也不严谨,但是没有必要使用wait()
    class T1 extends Thread {
        public void run() {
            for (int i= 65; i< 70; ++i) {
                 synchronized(Main.lockObj) {        
                    System.out.print(String.format("%d = ", i));               
                }
                Thread.yield();
            }
        }
    }class T2 extends Thread {
        public void run() {
            for (char i= 'A'; i< 'F'; ++i) {
                synchronized(Main.lockObj) {
                    System.out.println(i);
                    
                }
                Thread.yield();          
            }
        }
    }由于yield()不释放锁,所以要放在synchronized外面
      

  2.   

    notify只是释放锁,线程不一定执行,线程执行是要排队和优先级的。
      

  3.   

    notify释放锁吗?不要误导别人。notifty()只是唤醒此对象监视器上等待的单个线程,直到当前线程释放此对象上的锁,才有可能继续执行被唤醒的线程
      

  4.   


    对的!这个说法是准确的。notify只是唤醒了一个因为调用了wait而自愿阻塞的线程,它现在可以执行了,但是,能不能访问,要看该对该对象加锁的线程是否已经释放了锁(两种方式:第一该线程运行同步方法已经结束,第二该线程调用了wait方法,自愿阻塞)。
      

  5.   

    我一直有个误区,以为A线程通过wait临时释放锁,B线程通过notify唤醒A,B再释放锁之后一定会是刚才调用wait的线程重新获得锁。其实不然,如果还有其它线程也在积极的想获得锁的话,究竟是谁得到锁就不一定了。等效windows代码
    synchronized(obj)   WaitForSingleObject(obj)
    {                   ..
      obj.wait();       Release...()
                        WaitForSingleObject(obj)                     
    }                   Release...()也就是说,wait应该是释放之后再重新获得,也就是分两步来的,那最后谁获得锁都不一定了
      

  6.   

    在资源等待池中线程是没有顺序的,notify方法只是从等待池中任意选择一个线程恢复运行
    具体是那个没有保障你的需求其实可以这样思想,不需要睡眠    public static void test2() {        T3 t3 = new T3();
            T4 t4 = new T4();
            
            t3.start();
            t4.start();
        }
        
        public static Integer lockObj = new Integer(0);
    }class T3 extends Thread {
    public void run() {
    try {
    synchronized (Main.lockObj) {
    for (int i = 65; i < 70; ++i) {
    System.out.print(String.format("%d = ", i));
    Main.lockObj.notify();
    Main.lockObj.wait();
    }
    Main.lockObj.notify();//这一句很重要,不然T4的wait将没有人来唤醒
                          //程序会无法结束,这也表现了,在线程中切来换去
      //是很危险的极易造成死锁,小心+小心

    } catch (InterruptedException e) {
    e.printStackTrace();
    }
    }
    }class T4 extends Thread {
        public void run() {
         try{
         synchronized(Main.lockObj) {
         for (char i= 'A'; i< 'F'; ++i) {
                     System.out.println(i);
                     Main.lockObj.notify();
                     Main.lockObj.wait();
         }   
        
         }
         }catch(InterruptedException e){
         e.printStackTrace();
         }
        }
    }