JAVA多线程中synchronized,wait跟notify的关系
JAVA多线程中synchronized,wait和notify的关系
synchronized是和一个锁对象关联的,synchronized限制static方法的时候,
锁对象为这个类的class变量,相当于XXXClass.class.
synchronized限制非static方法的时候,锁对象为这个类的实例(相当于this).
synchronized限制一个对象实例的时候,如(synchronized (xlock)),锁对象为指定的这个对象实例,如xlock.
只有获得锁对象的锁的线程才能执行synchronized限制的代码.
synchronized限制static方法的时候,在某一时刻,同一个虚拟机只能有一个线程正在执行这个static方法,
因为锁对象是这个class的XXXClass.class实例,一个虚拟机只有一个XXXClass.class实例.
synchronized限制某一个类的非static方法的时候,对这个类的某一特定实例,
在某一时刻,同一个虚拟机只能有一个线程正在执行这个方法,但是可以同时执行多个实例的这个特定方法,因为锁对象不同.
wait,notify和notifyAll都只能在一个锁对象上调用,否则会发生如下异常:
java.lang.IllegalMonitorStateException: current thread not owner
下面的代码是合法的:第一个例子相当于调用了this.notifyAll();this这时候为锁对象.
唤醒在此对象监视器上等待的某一个线程.具体是哪一个可以认为是不确定的.
void notifyAll()
唤醒在此对象监视器上等待的所有线程。
void wait()
导致当前的线程等待,直到其他线程调用此对象的 notify()方法或 notifyAll()方法.
wait会释放占有的锁,notify和notifyAll不会释放占用的锁.
下面通过一个实例代码来讲解一下:
wait,主线程通过notifyAll唤醒两个子线程.
运行的结果为:
//NotifyWaitTest.lock.notifyAll(); //# point 1 有异常发生
*2,notifyAll会唤醒该锁对象上所有等待的线程.
*3,TestThread1中的run方法中wait之后的代码是synchronized,唤醒的两个线程是一个执行完成之后,另外一个才能执行.
*4,如果在main方法中改用下面的方式notify,在"sent notification over"之后两个子线程才会从
wait暂停的地方继续执行,因为notify并不释放锁,这时候main还占用NotifyWaitTest.lock锁对象的锁.
代码不是synchronized的,所以wakeup之后可以并行执行.
synchronized是和一个锁对象关联的,synchronized限制static方法的时候,
锁对象为这个类的class变量,相当于XXXClass.class.
synchronized限制非static方法的时候,锁对象为这个类的实例(相当于this).
synchronized限制一个对象实例的时候,如(synchronized (xlock)),锁对象为指定的这个对象实例,如xlock.
只有获得锁对象的锁的线程才能执行synchronized限制的代码.
synchronized限制static方法的时候,在某一时刻,同一个虚拟机只能有一个线程正在执行这个static方法,
因为锁对象是这个class的XXXClass.class实例,一个虚拟机只有一个XXXClass.class实例.
synchronized限制某一个类的非static方法的时候,对这个类的某一特定实例,
在某一时刻,同一个虚拟机只能有一个线程正在执行这个方法,但是可以同时执行多个实例的这个特定方法,因为锁对象不同.
wait,notify和notifyAll都只能在一个锁对象上调用,否则会发生如下异常:
java.lang.IllegalMonitorStateException: current thread not owner
下面的代码是合法的:第一个例子相当于调用了this.notifyAll();this这时候为锁对象.
public synchronized void sendNotification() throws Exception { notifyAll(); } synchronized (NotifyWaitTest.lock) { try { NotifyWaitTest.lock.notifyAll(); } catch (Exception e) { e.printStackTrace(); } }void notify()
唤醒在此对象监视器上等待的某一个线程.具体是哪一个可以认为是不确定的.
void notifyAll()
唤醒在此对象监视器上等待的所有线程。
void wait()
导致当前的线程等待,直到其他线程调用此对象的 notify()方法或 notifyAll()方法.
wait会释放占有的锁,notify和notifyAll不会释放占用的锁.
下面通过一个实例代码来讲解一下:
public class NotifyWaitTest { public static Class lock = NotifyWaitTest.class; public static void main(String[] args) throws Exception { // new TestThread1().start(); // new TestThread1().start(); new TestThread2().start(); new TestThread2().start(); Thread.sleep(3000); // NotifyWaitTest.lock.notifyAll(); //# poing 1 synchronized (NotifyWaitTest.lock) { try { System.out.println(Thread.currentThread().getName() + " sent notification all"); NotifyWaitTest.lock.notifyAll(); // System.out.println(Thread.currentThread().getName() + " sent notification 1"); // NotifyWaitTest.lock.notify(); // System.out.println(Thread.currentThread().getName() + " sent notification 2"); // Thread.sleep(3000); // NotifyWaitTest.lock.notify(); // System.out.println(Thread.currentThread().getName() + " sent notification over"); } catch (Exception e) { e.printStackTrace(); } } } } class TestThread1 extends Thread { public void run() { synchronized (NotifyWaitTest.lock) { try { System.out.println(Thread.currentThread().getName() + " wait for notification"); NotifyWaitTest.lock.wait(); System.out.println(Thread.currentThread().getName() + " wake up"); for (int i = 0; i < 3; i++) { Thread.sleep(1000); System.out.println(Thread.currentThread().getName() + " doing " + i); } } catch (Exception e) { e.printStackTrace(); } System.out.println(Thread.currentThread().getName() + " finished"); } } } class TestThread2 extends Thread { public void run() { synchronized (NotifyWaitTest.lock) { System.out.println(Thread.currentThread().getName() + " wait for notification"); try { NotifyWaitTest.lock.wait(); } catch (InterruptedException e) { e.printStackTrace(); } } System.out.println(Thread.currentThread().getName() + " wake up"); for (int i = 0; i < 3; i++) { try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(Thread.currentThread().getName() + " doing " + i); } } }在主线程里启动两个子线程,主线程和这两个线程用同一个锁对象,子线程启动后就进入
wait,主线程通过notifyAll唤醒两个子线程.
运行的结果为:
Thread-0 wait for notification Thread-1 wait for notification main sent notification all Thread-0 wake up Thread-0 doing 0 Thread-0 doing 1 Thread-0 doing 2 Thread-0 finished Thread-1 wake up Thread-1 doing 0 Thread-1 doing 1 Thread-1 doing 2 Thread-1 finished*1,如果不是在synchronized关联的锁对象调用notify,notifyAll或者wait会有异常.
//NotifyWaitTest.lock.notifyAll(); //# point 1 有异常发生
*2,notifyAll会唤醒该锁对象上所有等待的线程.
*3,TestThread1中的run方法中wait之后的代码是synchronized,唤醒的两个线程是一个执行完成之后,另外一个才能执行.
*4,如果在main方法中改用下面的方式notify,在"sent notification over"之后两个子线程才会从
wait暂停的地方继续执行,因为notify并不释放锁,这时候main还占用NotifyWaitTest.lock锁对象的锁.
System.out.println(Thread.currentThread().getName() + " sent notification 1"); NotifyWaitTest.lock.notify(); System.out.println(Thread.currentThread().getName() + " sent notification 2"); Thread.sleep(3000); NotifyWaitTest.lock.notify(); System.out.println(Thread.currentThread().getName() + " sent notification over"); 运行的结果为 Thread-0 wait for notification Thread-1 wait for notification main sent notification 1 main sent notification 2 main sent notification over Thread-0 wake up Thread-0 doing 0 Thread-0 doing 1 Thread-0 doing 2 Thread-0 finished Thread-1 wake up Thread-1 doing 0 Thread-1 doing 1 Thread-1 doing 2 Thread-1 finished如果在main方法中启动的是TestThread2,因为在TestThread2的run方法中wait之后的
代码不是synchronized的,所以wakeup之后可以并行执行.
new TestThread2().start(); new TestThread2().start(); 运行的结果是: Thread-0 wait for notification Thread-1 wait for notification main sent notification all Thread-0 wake up Thread-1 wake up Thread-0 doing 0 Thread-1 doing 0 Thread-0 doing 1 Thread-1 doing 1 Thread-0 doing 2 Thread-1 doing 2