19.wait与sleep的区别


 

 

waitsleep的区别

 引言

本节介绍wait方法与sleep方法的区别,一共有7件不同

 位置

首先来看第一点位置,sleep方法是线程方法,它位于thread内里面,而wait方法是锁方法,它位于object类里面,

这里展示的是sleep方法锁处的位置以及方法个数。

同样的这里展示的是wait方法锁处的位置以及方法个数。

 第二点

下面再来看第二点,是否需要当前线程拥有锁,调用sleep方法时,不需要当前线程拥有锁而调用wait方法时,则需要当前线程拥有锁。

现在看sleep方法实例,这里使当前线程休眠一秒钟,

package com.chenjie.executor.day19;


import com.chenjie.executor.day18.Task;

/**
 *
 *
 * @author chenjie
 * @version JDK 8
 * @className Main1 (此处以class为例)
 * @date 2024/5/27
 * @description TODO
 */
public class Main {

    /**
     *
     * @param args
     */
    public static void main(String[] args) {

        try {
            Thread.sleep(1000L);
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }
        System.out.println("人人都是程序员");

    }
}

从执行结果来看,调用sleep方法时,它不需要当前线程拥有锁。

再来看wait方法实例,这里使当前线程等待。

package com.chenjie.executor.day19;


/**
 *
 *
 * @author chenjie
 * @version JDK 8
 * @className Main1 (此处以class为例)
 * @date 2024/5/27
 * @description TODO
 */
public class Main1 {

    /**
     *
     * @param args
     */
    public static void main(String[] args) {
//        synchronized (Main1.class){
            try {
                 Main1.class.wait(1000L);
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
            System.out.println("人人都是程序员");

//        }
    }
}

从执行结果来看,若当前线程没有拥有锁程序则会发生异常,

所以我们需要在同步中调用wait方法,让线程获取锁。

package com.chenjie.executor.day19;


/**
 *
 *
 * @author chenjie
 * @version JDK 8
 * @className Main1 (此处以class为例)
 * @date 2024/5/27
 * @description TODO
 */
public class Main1 {

    /**
     *
     * @param args
     */
    public static void main(String[] args) {
        synchronized (Main1.class){
            try {
                 Main1.class.wait(1000L);
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
            System.out.println("人人都是程序员");

        }
    }
}

从执行结果来看,线程被等待没有引发异常。

 支持手动唤醒

下面再来看第三点,是否支持手动唤醒?

sleep方法不支持手动唤醒,而wait方法是支持手动唤醒的,

支持的方法有 notify,notifyall由于sleep方法不支持手动唤醒,所以这里就不再演示它了。 


下面只演示
wait方法的实例,自定义一个任务,任务内容,就是使当前线程等待,等待之后,输出一句话执行该任务,并调用锁对象task的notify和notifyall方法唤醒线程。

package com.chenjie.executor.day19;


import com.chenjie.executor.day18.Task;

/**
 *
 *
 * @author chenjie
 * @version JDK 8
 * @className Main1 (此处以class为例)
 * @date 2024/5/27
 * @description TODO
 */
public class Main2 {

    /**
     *
     * @param args
     */
    public static void main(String[] args) {
        Task task=new Task();
        Thread thread = new Thread(task,"thread");
        thread.start();
        try {
            Thread.sleep(1000L);
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }
        synchronized(task){
            task.notify();
        }
    }

}

从执行结果来看,线程等待一秒后被唤醒。

 是否支持自动唤醒

下面再来看第四点,是否支持自动唤醒,两个方法都支持自动唤醒,都可以指定超时时间。

先来看sleep方法实例,这里使当前线程休眠一秒钟。

package com.chenjie.executor.day19;


import com.chenjie.executor.day18.Task;

/**
 *
 *
 * @author chenjie
 * @version JDK 8
 * @className Main1 (此处以class为例)
 * @date 2024/5/27
 * @description TODO
 */
public class Main {

    /**
     *
     * @param args
     */
    public static void main(String[] args) {

        try {
            Thread.sleep(1000L);
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }
        System.out.println("人人都是程序员");

    }
}

从执行结果来看,程序经过一秒钟之后输出该内容。

再来看wait方法实例,这里使当前线程等待并指定超时时间为一秒钟。

package com.chenjie.executor.day19;


/**
 *
 *
 * @author chenjie
 * @version JDK 8
 * @className Main1 (此处以class为例)
 * @date 2024/5/27
 * @description TODO
 */
public class Main1 {

    /**
     *
     * @param args
     */
    public static void main(String[] args) {
        synchronized (Main1.class){
            try {
                 Main1.class.wait(1000L);
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
            System.out.println("人人都是程序员");

        }
    }
}

从执行结果来看,程序经过一秒钟之后输出该内容。

 是否支持中断

下面我们来看第五点,是否支持中断。sleep方法和wait方法都支持中断,也就是支持interrupt方法,只不过他们被中断以后都会发生线程中断异常。

下面来看一下示例代码。首先来看sleep方法实例,制定一个任务,任务内容就是使当前线程休眠一秒钟,

package com.chenjie.executor.day19;


/**
 * packageName com.chenjie.executor.day14
 *
 * @author chenjie
 * @version JDK 8
 * @className TicketTask (此处以class为例)
 * @date 2024/5/28
 * @description TODO
 */
public class Task1 implements Runnable {


    @Override
    public void run() {
                try {
                    Thread.sleep(1000L);
                } catch (InterruptedException e) {
                    throw new RuntimeException(e);
                }
                System.out.println("人人都是程序员");

        }


    }

然后执行该任务,接着中断执行任务的线程。从执行结果来看,线程休眠后立马被中断并引发了异常。

再来看wait方法实例,任务内容变成了使当前线程等待执行任务的步骤不变。下面来看看执行结果。 

package com.chenjie.executor.day19;


/**
 * packageName com.chenjie.executor.day14
 *
 * @author chenjie
 * @version JDK 8
 * @className TicketTask (此处以class为例)
 * @date 2024/5/28
 * @description TODO
 */
public class Task implements Runnable {


    @Override
    public void run() {
            synchronized (this) {
                try {
                    this.wait();
                } catch (InterruptedException e) {
                    throw new RuntimeException(e);
                }
                System.out.println("人人都是程序员");
            }
        }


    }

从执行结果来看,线程等待后立马被中断,并引发了线程中断异常。

 

 是否释放锁

下面我们来看第六点,是否释放锁?这里说的是当方法被调用时,此时锁是否被释放?

sleep方法被调用时不会释放速,而wait方法被调用时会立即释放锁。

先来看看sleep方法实例,制定一个任务,任务内容是使当前线程休眠三秒钟,

package com.chenjie.executor.day19;


/**
 * packageName com.chenjie.executor.day14
 *
 * @author chenjie
 * @version JDK 8
 * @className TicketTask (此处以class为例)
 * @date 2024/5/28
 * @description TODO
 */
public class Task2 implements Runnable {


    @Override
    public void run() {
        synchronized (this){// 添加同步块
            try {
                Thread.sleep(3000L);
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
            System.out.println(System.currentTimeMillis()+"人人都是程序员");
        }
        }


    }

然后去执行该任务,这里使主线程去争夺thread的线程的锁。

package com.chenjie.executor.day19;


/**
 *
 *
 * @author chenjie
 * @version JDK 8
 * @className Main1 (此处以class为例)
 * @date 2024/5/27
 * @description TODO
 */
public class Main6 {

    /**
     *
     * @param args
     */
    public static void main(String[] args) throws InterruptedException {
        Task2 task=new Task2();
        Thread thread = new Thread(task,"thread");
        thread.start();
        Thread.sleep(100L);
        synchronized (task){
            System.out.println("人人都是程序员1");

        }
    }

}

从执行结果来看,三秒后内容才被输出,说明调用sleep方法时不会释放锁。 

再来看wait方法实例,任务内容变成使当前线程等待,其他的不变。

package com.chenjie.executor.day19;


/**
 * packageName com.chenjie.executor.day14
 *
 * @author chenjie
 * @version JDK 8
 * @className TicketTask (此处以class为例)
 * @date 2024/5/28
 * @description TODO
 */
public class Task3 implements Runnable {


    @Override
    public void run() {
            synchronized (this) {
                try {
                    this.wait();
                } catch (InterruptedException e) {
                    throw new RuntimeException(e);
                }
                System.out.println("人人都是程序员");
            }
        }


    }

从执行结果来看,内容立马被输出,说明调用wait方法会立即释放锁。main方法没有结束的原因是还有线程在等待

线程状态

下面我们再来看最后一点,线程状态,sleep方法它只有一种状态,timed_waiting,而wait方法它有两种状态,waiting和timed_waiting

为什么wait会有两种状态?因为wait一共有三个方法,其中第一个方法是手动唤醒,其余两个是超时自动唤醒,前者的线程状态是waiting,后者线程的状态是timed_waiting。 

先来看sleep方法实例,任务还是使当前线程休眠三秒钟,执行任务。

package com.chenjie.executor.day19;


/**
 *
 *
 * @author chenjie
 * @version JDK 8
 * @className Main1 (此处以class为例)
 * @date 2024/5/27
 * @description TODO
 */
public class Main8 {

    /**
     *
     * @param args
     */
    public static void main(String[] args) throws InterruptedException {
        Task2 task=new Task2();
        Thread thread = new Thread(task,"thread");
        thread.start();
        Thread.sleep(1000L);
            System.out.println(thread.getState());


    }

}

下面来看看执行结果。从执行结果来看,休眠中的线程,它的状态是timed_waiting,

再来看看wait的方法实例,它有两种现成状态,现在演示第一种线程状态,任务内容变成使当前线程等待其他的不变。

package com.chenjie.executor.day19;


/**
 * packageName com.chenjie.executor.day14
 *
 * @author chenjie
 * @version JDK 8
 * @className TicketTask (此处以class为例)
 * @date 2024/5/28
 * @description TODO
 */
public class Task implements Runnable {


    @Override
    public void run() {
            synchronized (this) {
                try {
                    this.wait();
                } catch (InterruptedException e) {
                    throw new RuntimeException(e);
                }
                System.out.println("人人都是程序员");
            }
        }


    }

下面来看一下执行结果,从执行结果来看,等待中的线程它的状态是waiting。

package com.chenjie.executor.day19;


/**
 *
 *
 * @author chenjie
 * @version JDK 8
 * @className Main1 (此处以class为例)
 * @date 2024/5/27
 * @description TODO
 */
public class Main9 {

    /**
     *
     * @param args
     */
    public static void main(String[] args) throws InterruptedException {
        Task task=new Task();
        Thread thread = new Thread(task,"thread");
        thread.start();
        Thread.sleep(1000L);
            System.out.println(thread.getState());


    }

}

再看wait的第二种状态测试,等待超时时间为三秒钟,其他的不变。

package com.chenjie.executor.day19;


/**
 * packageName com.chenjie.executor.day14
 *
 * @author chenjie
 * @version JDK 8
 * @className TicketTask (此处以class为例)
 * @date 2024/5/28
 * @description TODO
 */
public class Task4 implements Runnable {


    @Override
    public void run() {
            synchronized (this) {
                try {
                    this.wait(3000L);
                } catch (InterruptedException e) {
                    throw new RuntimeException(e);
                }
                System.out.println("人人都是程序员");
            }
        }


    }

下面来看一下执行结果。从执行结果来看,超时等待中的线程他的状态是timed_waiting。 

 总结

最后我们来总结一下本节的内容。本节介绍了wait方法和sleep方法的区别,总结了7点不同,这里就不再赘述了。大家可以截屏保存,以供日后使用。 

 

posted @ 2022-05-03 20:09  小陈子博客  阅读(305)  评论(0编辑  收藏  举报