Java:sleep、wait、notify、notifyAll

记得以前初学Java时老是搞不清这几个方法,现在稍微记录一下。


概述

sleep是Thread这个类的一个静态方法,调用时则当前线程睡眠多长时间;
wait是Object类的一个方法,某个对象调用wait方法时,当前线程等待多长时间。某个对象调用wait/notify/notifyAll方法前,必须获得这个对象的锁,否则会抛出java.lang.IllegalMonitorStateException异常。


sleep与wait

sleep与wait方法的最大不同就是线程进行同步时,sleep不会释放锁,而wait会。

Demo1

public class Main {

    public static void main(String[] args) throws InterruptedException {
        // TODO Auto-generated method stub
        Task task = new Task();
        new Thread(task).start();
        new Thread(task).start();
        new Thread(task).start();
    }

    private static class Task implements Runnable {

        @Override
        public void run() {
            // TODO Auto-generated method stub
            try {
                Thread.sleep(2000);
            } catch (InterruptedException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
            print();
        }

        private void print() {
            System.out.println(Thread.currentThread().toString() + " "
                    + System.currentTimeMillis());
        }
    }

}

这个结果会是怎样呢?

Thread[Thread-0,5,main] 1446863651674
Thread[Thread-2,5,main] 1446863651675
Thread[Thread-1,5,main] 1446863651675

三条线程同时完成。当主线程启动三条线程时,三条线程都睡眠2秒,最终也一起结束睡眠,退出run方法,线程终结。

Demo2
我们将睡眠方法外面加一个对象锁

synchronized (this) {
    try {
        Thread.sleep(2000);
    } catch (InterruptedException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    }
}

打印结果:

Thread[Thread-0,5,main] 1446863850163
Thread[Thread-2,5,main] 1446863852163
Thread[Thread-1,5,main] 1446863854163

三条线程隔2秒完成。当主线程启动三条线程时,首先某一条线程获得了对象锁,其他线程进入同步阻塞状态,这条线程睡眠2秒,睡醒后释放对象锁,退出run方法,第一条线程终结。第二条线程在第一条线程释放对象锁后进行同样的步骤。

Demo3
我们将Thread.sleep(2000)方法改为this.wait(2000)

synchronized (this) {
    try {
        this.wait(2000);
    } catch (InterruptedException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    }
}

打印结果:

Thread[Thread-2,5,main] 1446864186704
Thread[Thread-1,5,main] 1446864186705
Thread[Thread-0,5,main] 1446864186704

三条线程同时完成。当主线程启动三条线程时,首先某一条线程获得了对象锁,其他线程进入同步阻塞状态,这个对象锁调用wait(2000)方法,当前线程释放锁并等待2秒,等待完毕后退出run方法,线程终结。第二条线程在第一条线程释放对象锁后进行同样的步骤。

通过以上三个Demo可以知道,sleep和wait的最大区别就是sleep不会释放对象锁,而wait会。


notify与notifyAll

其实这两个还是很容易理解的,一个是随机唤醒某一条线程,另外一个是唤醒所有线程。

Demo1

public class Main {

    public static void main(String[] args) throws InterruptedException {
        // TODO Auto-generated method stub
        Task task = new Task();
        new Thread(task).start();
        new Thread(task).start();
        new Thread(task).start();
        Thread.sleep(1); // 保证三条线程都已经调用了wait
        synchronized (Task.class) {
            Task.class.notify();
        }
    }

    private static class Task implements Runnable {

        @Override
        public void run() {
            // TODO Auto-generated method stub
            synchronized (Task.class) {
                try {
                    Task.class.wait();
                } catch (InterruptedException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
            }
            print();
        }

        private void print() {
            System.out.println(Thread.currentThread().toString() + " "
                    + System.currentTimeMillis());
        }
    }

}

打印结果:

Thread[Thread-0,5,main] 1446864797683

只有一条线程被唤醒,另外两条线程仍然处于等待状态,所以程序并未结束。

Demo2
将主线程的唤醒方法改为notifyAll

synchronized (Task.class) {
    Task.class.notifyAll();
}

打印结果:

Thread[Thread-1,5,main] 1446864969393
Thread[Thread-2,5,main] 1446864969393
Thread[Thread-0,5,main] 1446864969393

三条线程都被唤醒了。

某个对象调用wait/notify/notifyAll方法前,必须获得这个对象的锁,否则会抛出java.lang.IllegalMonitorStateException异常。如果我们将对象锁换为this,则调用wait时也需要this对象。

synchronized (this) {
    try {
        this.wait();
    } catch (InterruptedException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    }
}

调用notify/notifyAll时同样需要代表当前对象是task引用。

Task task = new Task();
......
synchronized (task) {
    task.notifyAll();
}

synchronized方法的对象锁

synchronized方法的对象锁是当前对象,即this。

public class Main {

    public static void main(String[] args) {
        // TODO Auto-generated method stub
        Task task = new Task();
        new Thread(task).start();
        new Thread(new Runnable() {

            @Override
            public void run() {
                // TODO Auto-generated method stub
                task.sleep1();
            }
        }).start();
        new Thread(new Runnable() {

            @Override
            public void run() {
                // TODO Auto-generated method stub
                task.sleep2();
            }
        }).start();
    }

    private static class Task implements Runnable {

        @Override
        public void run() {
            // TODO Auto-generated method stub
            synchronized (this) {
                try {
                    Thread.sleep(2000);
                } catch (InterruptedException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
            }
            print();
        }

        private void print() {
            System.out.println(Thread.currentThread().toString() + " "
                    + System.currentTimeMillis());
        }

        private synchronized void sleep1() {
            try {
                Thread.sleep(2000);
            } catch (InterruptedException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
            print();
        }

        private synchronized void sleep2() {
            try {
                Thread.sleep(2000);
            } catch (InterruptedException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
            print();
        }
    }

}

打印结果:

Thread[Thread-0,5,main] 1446865583845
Thread[Thread-2,5,main] 1446865585844
Thread[Thread-1,5,main] 1446865587844

可以看到三条线程是隔2秒完成的,线程同步的效果出来了,也说明synchronized方法的对象锁为this。如果将run方法同步块的对象锁this改为Task.class呢?

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值