wait
wait方法是Object中的方法,这个方法的功能特性:
1).执行wait方法的前提是当前线程已经获取到对象的锁,也就是wait方法必须在synchronized修饰的代码块或者方法中使用。
2).执行wait之后,会失去锁的所有权
3).wait方法执行后会一直等待,直到被调用notify()、notifyAll()或者所在线程被中断。
4).被调用notify()或者notifyAll()后,线程还是会等待,直到拥有锁的所有权,才会继续往下执行。
下面举个例子:
public static void main(String[] args) throws InterruptedException {
Object lock1 = new Object();
Thread t1 = new Thread(new Test().new Tt1(lock1));
Thread t2 = new Thread(new Test().new Tt2(lock1));
t1.start();
Thread.sleep(1000);
t2.start();
}
class Tt1 implements Runnable{
private Object lock1;
public Tt1(Object lock1) {
this.lock1 = lock1;
}
@Override
public void run() {
try {
System.out.println(this.getClass()+"-------1");
synchronized (lock1) {
Thread.sleep(2000);
System.out.println("waiting start");
lock1.wait();
}
System.out.println("waiting end");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
class Tt2 implements Runnable{
private Object lock1;
public Tt2(Object lock1) {
this.lock1 = lock1;
}
@Override
public void run() {
System.out.println(this.getClass()+"-------1");
synchronized (lock1) {
try {
System.out.println(this.getClass()+"-------2");
lock1.notify();
Thread.sleep(1000);
System.out.println(this.getClass()+"-------3");
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
执行结果:
class Test$Tt1-------1
class Test$Tt2-------1
waiting start
class Test$Tt2-------2
class Test$Tt2-------3
waiting end
分析一下:
第1、2行:t1和t2启动,t1先获取到锁所以t2一直被阻塞住
第3、4行:t1中执行了wait,锁被释放,所以t2继续执行下去。
第5、6行:t2中调用了notify()但是t1没有马上执行,因为锁现在是被t2拥有,等t2执行完成释放锁后,t1继续执行。
notify、notifyAll
notify已经在上面有提到过,notify和notifyAll 的作用是唤醒正在wait的线程,notify是随机唤醒wait线程中的一个,notifyAll 则是唤醒全部。
1).执行notify、notifyAll 方法的前提是当前线程已经获取到对象的锁,也就是必须在synchronized修饰的代码块或者方法中使用。这个和wait是一样的。
2).被调用notify()或者notifyAll()后,线程还是会等待,直到拥有锁的所有权,才会继续往下执行。
3)notify、notifyAll不会释放锁,这个与wait不同。
释放和不释放锁
在多线程的操作中,锁的释放与否是必须要清楚的,wait是会释放锁,而notify(notifyAll)则不会。先举个wait的例子:
public static void main(String[] args) throws InterruptedException {
Object lock1 = new Object();
Thread t1 = new Thread(new Test().new Tt1(lock1));
Thread t2 = new Thread(new Test().new Tt2(lock1));
t1.start();
Thread.sleep(100);
t2.start();
}
class Tt1 implements Runnable{
private Object lock1;
public Tt1(Object lock1) {
this.lock1 = lock1;
}
@Override
public void run() {
try {
synchronized (lock1) {
System.out.println(Thread.currentThread().getName()+"---start");
lock1.wait();
Thread.sleep(3000);
System.out.println(Thread.currentThread().getName()+"---end");
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
class Tt2 implements Runnable{
private Object lock1;
public Tt2(Object lock1) {
this.lock1 = lock1;
}
@Override
public void run() {
synchronized (lock1) {
try {
System.out.println(Thread.currentThread().getName()+"---start");
System.out.println(Thread.currentThread().getName()+"---end");
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
执行结果:
Thread-0---start
Thread-1---start
Thread-1---end
Thread-0执行wait后马上释放了锁,所以Thread-1很快接着就执行。
再来notify的例子,其实就是把上一个例子wait()改成nofity():
public static void main(String[] args) throws InterruptedException {
Object lock1 = new Object();
Thread t1 = new Thread(new Test().new Tt1(lock1));
Thread t2 = new Thread(new Test().new Tt2(lock1));
t1.start();
Thread.sleep(100);
t2.start();
}
class Tt1 implements Runnable{
private Object lock1;
public Tt1(Object lock1) {
this.lock1 = lock1;
}
@Override
public void run() {
try {
synchronized (lock1) {
System.out.println(Thread.currentThread().getName()+"---start");
lock1.notify();
Thread.sleep(3000);
System.out.println(Thread.currentThread().getName()+"---end");
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
class Tt2 implements Runnable{
private Object lock1;
public Tt2(Object lock1) {
this.lock1 = lock1;
}
@Override
public void run() {
synchronized (lock1) {
try {
System.out.println(Thread.currentThread().getName()+"---start");
System.out.println(Thread.currentThread().getName()+"---end");
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
执行结果:
Thread-0---start
Thread-0---end
Thread-1---start
Thread-1---end
可见Thread-0在执行nofity后并没有释放锁,而是等待代码块执行完之后才释放锁,Thread-1才能继续执行。
必须先获取锁
无论是notify还是wait都是要先获取锁,既必须在synchronized内使用,举个反例:
public static void main(String[] args) throws InterruptedException {
Object lock1 = new Object();
Thread t1 = new Thread(new Test().new Tt1(lock1));
t1.run();
}
class Tt1 implements Runnable{
private Object lock1;
public Tt1(Object lock1) {
this.lock1 = lock1;
}
@Override
public void run() {
try {
lock1.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
执行结果:
Exception in thread "main" java.lang.IllegalMonitorStateException
at java.lang.Object.wait(Native Method)
at java.lang.Object.wait(Object.java:502)
at Test$Tt1.run(Test.java:24)
at java.lang.Thread.run(Thread.java:748)
at Test.main(Test.java:11)
wait()遇到interrupt()
之前说道interrupt(),并不会直接中断线程,而是会给线程一个中断标志,而且包括sleep、wait、join会抛出InterruptedException。
public static void main(String[] args) throws InterruptedException {
Object lock1 = new Object();
Thread t1 = new Thread(new Test().new Tt1(lock1));
t1.start();
Thread.sleep(100);
t1.interrupt();
}
class Tt1 implements Runnable{
private Object lock1;
public Tt1(Object lock1) {
this.lock1 = lock1;
}
@Override
public void run() {
synchronized (lock1) {
try {
System.out.println(Thread.currentThread().getName()+"---start");
lock1.wait();
System.out.println(Thread.currentThread().getName()+"---end");
}catch (InterruptedException e) {
System.out.println("线程被中断了");;
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
执行结果:
Thread-0---start
线程被中断了
notifyAll和nofity
notifyAll和nofity唯一的不同就是,可以唤醒全部和唤醒一个, 先举个nofity的例子
public static void main(String[] args) throws InterruptedException {
Object lock1 = new Object();
Thread t1 = new Thread(new Test().new Tt1(lock1));
Thread t2 = new Thread(new Test().new Tt1(lock1));
Thread t3 = new Thread(new Test().new Tt2(lock1));
t1.start();
Thread.sleep(100);
t2.start();
Thread.sleep(100);
t3.start();
}
class Tt1 implements Runnable{
private Object lock1;
public Tt1(Object lock1) {
this.lock1 = lock1;
}
@Override
public void run() {
synchronized (lock1) {
try {
System.out.println(Thread.currentThread().getName()+"---start");
System.out.println(Thread.currentThread().getName()+"---wait");
lock1.wait();
System.out.println(Thread.currentThread().getName()+"---end");
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
class Tt2 implements Runnable{
private Object lock1;
public Tt2(Object lock1) {
this.lock1 = lock1;
}
@Override
public void run() {
synchronized (lock1) {
try {
System.out.println(Thread.currentThread().getName()+"---start");
System.out.println(Thread.currentThread().getName()+"---notify");
lock1.notify();
System.out.println(Thread.currentThread().getName()+"---end");
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
执行结果:
Thread-0---start
Thread-0---wait
Thread-1---start
Thread-1---wait
Thread-2---start
Thread-2---notify
Thread-2---end
Thread-0---end
Thread-0和Thread-1在wait,Thread-2执行了notify,但只有Thread-0被唤醒,重新开始执行,Thread-1还在wait。
再来看看nofityAll:
public static void main(String[] args) throws InterruptedException {
Object lock1 = new Object();
Thread t1 = new Thread(new Test().new Tt1(lock1));
Thread t2 = new Thread(new Test().new Tt1(lock1));
Thread t3 = new Thread(new Test().new Tt2(lock1));
t1.start();
Thread.sleep(100);
t2.start();
Thread.sleep(100);
t3.start();
}
class Tt1 implements Runnable{
private Object lock1;
public Tt1(Object lock1) {
this.lock1 = lock1;
}
@Override
public void run() {
synchronized (lock1) {
try {
System.out.println(Thread.currentThread().getName()+"---start");
System.out.println(Thread.currentThread().getName()+"---wait");
lock1.wait();
System.out.println(Thread.currentThread().getName()+"---end");
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
class Tt2 implements Runnable{
private Object lock1;
public Tt2(Object lock1) {
this.lock1 = lock1;
}
@Override
public void run() {
synchronized (lock1) {
try {
System.out.println(Thread.currentThread().getName()+"---start");
System.out.println(Thread.currentThread().getName()+"---notifyAll");
lock1.notifyAll();
System.out.println(Thread.currentThread().getName()+"---end");
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
执行结果:
Thread-0---start
Thread-0---wait
Thread-1---start
Thread-1---wait
Thread-2---start
Thread-2---notifyAll
Thread-2---end
Thread-1---end
Thread-0---end
Thread-2执行了notifyAll后,Thread-1和Thread-0都被唤醒。
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。