线程常用方法辨析(1)

2021-01-14 15:45:05 浏览数 (2)

线程常用方法辨析(1)

概述


1.sleep()方法

2.wait()方法

3.notify()/notifyAll()

4.总结

第1节 sleep()方法

1. sleep()方法的作用是让当前线程暂停指定的时间(毫秒)

2. sleep()方法只是暂时让出CPU的执行权,并不释放锁

3. 由于对象锁没有被释放,其他线程仍然无法访问这个对象

4. sleep()方法不需要在同步的代码块中执行,wait()方法必须要在同步的代码块中执行

5. sleep()可以通过interrupt()方法打断线程的暂停状态

6. sleep()只是线程的操作,用于短时间暂停线程,不涉及线程间通信

7. sleep()是Thread类的方法

代码语言:javascript复制
public class SleepTest {

    /**
     * sleep()方法不会释放锁,因此线程是按照先后顺序执行的
     */
    public synchronized void sleepMethod(){
        System.out.println("Sleep start : "
                  Thread.currentThread().getName());
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("Sleep end : "
                  Thread.currentThread().getName());
    }

    /**
     * wait()方法会释放锁,因此一旦调用wait()方法就会造成其他线程运行
     */
    public synchronized void waitMethod(){
        System.out.println("Wait start : "
                  Thread.currentThread().getName());
        synchronized (this){
            try {
                wait(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        System.out.println("Wait end :"
                  Thread.currentThread().getName());
    }

    public static void main(String[] args) {

        final SleepTest test1 = new SleepTest();

        for(int i = 0; i < 5; i  ){
            new Thread(() -> test1.sleepMethod()).start();
        }


        try {
            //暂停十秒,等上面程序执行完成
            Thread.sleep(10000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        System.out.println("-----分割线-----");

        final SleepTest test2 = new SleepTest();

        for(int i = 0; i < 5; i  ){
            new Thread(() -> test2.waitMethod()).start();
        }

    }
}

执行结果如下:

代码语言:javascript复制
Sleep start : Thread-0
Sleep end : Thread-0
Sleep start : Thread-4
Sleep end : Thread-4
Sleep start : Thread-3
Sleep end : Thread-3
Sleep start : Thread-2
Sleep end : Thread-2
Sleep start : Thread-1
Sleep end : Thread-1
-----分割线-----
Wait start : Thread-5
Wait start : Thread-6
Wait start : Thread-8
Wait start : Thread-7
Wait start : Thread-9
Wait end :Thread-6
Wait end :Thread-8
Wait end :Thread-9
Wait end :Thread-7
Wait end :Thread-5

第2节 wait()方法


1. wait()/notify()方法通常成对出现

2. wait()/notify()方法需要获取对象锁方可调用

3. wait()/notify()方法要写在同步代码块或者同步方法内

4. 一旦调用wait()方法,其他线程将可以访问这个对象

5. 当一个线程执行到wait()方法时,它就进入到一个和该对象相关的等待池中,

同时失去了对象的锁,可以允许其它的线程执行一些同步操作。

6. wait()可以通过interrupt()方法打断线程的暂停状态,从而使线程立刻抛出中断异常

7. 重获对象锁:

a)设置wait()方法的参数,如wait(1000)表明借出去1秒钟之后,自动收回锁

b)让借锁的线程通知(notify)当前线程,借锁线程用完了当前线程马上就收回来

8. wait()/notify()是Object类的方法

第3节 notify()/notifyAll()


1. notify()唤醒在此对象监视器(对象锁)上等待的单个线程

2. 当它被一个notify()方法唤醒时,等待池中的线程就被放到了锁池中

(synchronized部分会详细讲解等待池和锁池,此处简单理解即可)

3. 该线程将等待从锁池中获得锁,然后回到wait()前的现场

4. notifyAll()唤醒在此对象监视器(对象锁)上等待的所有线程

5. 唤醒的线程的顺序——LIFO(Last In First Out,后进先出)

6. wait()/notify()/notifyAll()涉及线程间的通信

代码语言:javascript复制
public class WaitClassDemo {

    private static SimpleDateFormat sdf = new SimpleDateFormat("HH:mm:ss");

    public static void main(String[] args) {
        Object obj = new Object();
        for (int i = 0; i < 5; i  ) {
            new WaitThread(i   "", obj).start();
        }
        new NotifyThread(obj).start();
    }

    /**
     * 调用wait()方法的线程
     */
    static class WaitThread extends Thread {

        Object obj;

        public WaitThread(String name, Object obj) {
            setName("WaitThread"   name);
            this.obj = obj;
        }

        @Override
        public void run() {
            synchronized (obj) {
                System.out.println(sdf.format(new Date())   " "   getName()   " before wait()");
                try {
                    obj.wait();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println(sdf.format(new Date())   " "   getName()   " after wait()");
            }
        }
    }

    /**
     * 调用notify()/notifyAll()
     */
    static class NotifyThread extends Thread {

        Object obj;

        public NotifyThread(Object obj) {
            setName("NotifyThread");
            this.obj = obj;
        }

        @Override
        public void run() {
            synchronized (obj) {
                try {
                    Thread.sleep(5000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println(sdf.format(new Date())   " NotifyThread before notify()");
                // 唤醒所有线程 用notifyAll()会按照后进先出(LIFO)的原则恢复线程
                obj.notifyAll();
                try {
                    Thread.sleep(5000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println(sdf.format(new Date())   " NotifyThread after notify()");
            }
        }
    }
}

执行结果如下:

代码语言:javascript复制
20:11:44 WaitThread0 before wait()
20:11:44 WaitThread4 before wait()
20:11:44 WaitThread3 before wait()
20:11:44 WaitThread2 before wait()
20:11:44 WaitThread1 before wait()
20:11:49 NotifyThread before notify()
20:11:54 NotifyThread after notify()
20:11:54 WaitThread1 after wait()
20:11:54 WaitThread2 after wait()
20:11:54 WaitThread3 after wait()
20:11:54 WaitThread4 after wait()
20:11:54 WaitThread0 after wait()

第4节 总结


1. wait()、notify()、notifyAll()是三个定义在Object类里的方法,可以用来控制线程的状态

2. 调用了wait()方法就会使持有该对象的线程把该对象的控制权交出去,然后处于等待状态

3. 对象调用了notify()方法就会通知某个正在等待这个对象的控制权的线程可以继续运行

4. 对象调用了notifyAll()方法就会通知所有等待这个对象控制权的线程继续运行

5. wait()方法有三个重载的方法wait()/wait(long)/wait(long,int)

6. sleep()方法的作用是让当前线程暂停指定的时间

7. sleep()方法只是暂时让出CPU的执行权,并不释放锁

0 人点赞