上一篇关于线程的博客简单梳理了一下多线程的一些基本概念,今天这篇博客再进行多线程编程中一些核心的方法进行简单的梳理和总结,主要是wait,sleep和notify方法以及中断的概念

一、中断概念。

  在多线程中,中断可以理解为线程之间一种特殊的通讯手段或者说相互控制的一种方式。调用某个线程对象的中断方法--interrupt可以控制该线程,使其抛出interruptedException,从而中断线程的执行。

  中断很多时候发生在线程之间需要同步或者线程执行之间有关联时(个人理解),例如:线程A要等到线程B执行完某段代码方可正常执行,但是,线程B有可能会出现因为阻塞问题(例如某个时候网络不好,流操作阻塞时间长)执行时间过长,而线程A这时不想等到线程B执行这么久,直接中断B线程以获得较快的响应速度(这种情况可以类比网络不好时,一般只是等待一定时间,而不会无限等待下去)。

  总的来说,中断提供了一种除了外界线程控制线程执行去向的手段。

二、sleep方法

  相信对多线程有哪怕一点了解的伙伴估计都知道sleep方法,它可以让当前线程进入休眠状态,该状态就是,什么都不做的状态,当时却不会释放持有的对象锁。

sleep方法较为简单,简单上个例子吧:

public static void main(String[] args) {
new Thread(new Runnable() {
public void run() {
System.out.println("即将调用sleep方法");
try {
/*说明:sleep方法是Thread中的静态方法,在该线程中调用该方法表示的是使该线程陷入睡眠状态,参数的数值是睡眠的时间长度
* 同时,该方法会抛出异常,所以需要进行捕获或者抛出,该异常的抛出是因为外部线程程序对该线程进行了interrupt方法调用,中断了线程,这个后面会具体讲
*/
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}).start();
}

当然,sleep方法如果持有锁是,sleep期间是不会释放的,这里不举例子测试了。

下面简单说说,sleep方法被中断的操作过程。线程的中断,一般是在外部线程直接调用该线程对象的interrupt方法使得当前线程抛出异常而中断,具体参考代码,注意看注释:

public class SynchRnizedAndLock {
public static void main(String[] args) throws InterruptedException {
Thread t1 = new Thread(new DemoSleepMethodTest());
t1.start();
//调用interrupt方法
Thread.sleep(1000);
System.out.println("调用了interrupt方法");
t1.interrupt();//在主线程执行中断方法 }
}
//sleep方法中断测试例子
class DemoSleepMethodTest implements Runnable{
public void run() {
System.out.println("执行了sleep方法");
try {
Thread.sleep(10000);//调用sleep方法
System.out.println("sleep方法后面的代码,由于被中断了,不会执行到");
} catch (InterruptedException e1) {
System.out.println("sleep方法被中断");
}
}
}

sleep方法较为简单,相信看完上面的例子也差不多理解了。sleep方法一般是在等待某些资源的时候,程序检测到有可能需要等待的时间较长,所以使自己陷入一种休眠的状态,腾出CPU的资源给其他线程使用。当然,线程的休眠不会影响到其他的线程,这点和wait方法就有所差别了。

搞定sleep方法,下面进行wait方法的简单总结。

三、wait方法。

  和sleep方法一样的是,wait方法也会使得当前线程停止执行,但是,wait方法的具体特性和sleep方法还是有很多区别的,下面一一讲解。

  首先,简单介绍下wait方法的用法,它和sleep用法差别还是蛮大的,具体请看代码注释:

//测试用例对象
class Test{
//定义两个对象
static Object object1 = new Object();
static Object object2 = new Object();
}
//主类
public class SynchRnizedAndLock {
public static void main(String[] args) throws InterruptedException {
Thread t1 = new Thread(new DemoSleepMethodTest());
t1.start();
//调用interrupt方法
Thread.sleep(1000);
System.out.println("调用了interrupt方法");
t1.interrupt();
}
}//wait中断方法测试例子
class DemoWaitMethodTest implements Runnable{
public void run() {
System.out.println("准备执行wait方法");
synchronized(Test.object1){
try {
System.out.println("调用了wait方法");
//调用wait方法,注意的是,wait方法必须在同步代码块中执行,因为它是调用同步数据对象的wait方法而不是线程本身的wait方法
Test.object1.wait();
          System.out.println("wait后面的方法由于被中断了,不会被执行到");
} catch (InterruptedException e) {
//当其他线程调用了被线程的interrupt方法时,就会中断该线程,此时会抛出异常
System.out.println("wait方法被中断");
}
}
}
}

上面的代码可以看到(注释也说了):wait方法调用的并不是线程的wait方法,而是该线程同步快中的参数对象即被同步的数据对象的wait方法;所以,wait方法必须是放在同步代码块里面的。

和sleep方法一样,wait方法也需要捕获处理异常,抛出异常的情况和sleep类似:有外部线程调用了该线程对象的interrupt方法。

四、notify(all)方法和wait方法的关系

  notify方法用于唤醒一个之前调用了的wait方法而陷入等待的一个线程。同样的,该方法也必须要在同步代码块里面执行,调用的是同步对象的notify方法。具体的话看下面一大坨代码吧,注意看注释了:

public class NotifyTest {
public static void main(String[] args) throws InterruptedException {
new Thread(new WaitNotifyTestDemo()).start();
Thread.sleep(1000);
new Thread(new NotifyTestDemo()).start();
} }
//notify方法测试
class NotifyTestDemo implements Runnable{
public static void notifyTestMethod(){
//notify方法也必须在synchronized代码块里面
synchronized(Test.object1){
System.out.println("即将执行notify方法");
/*注意,这里和wait方法一样,notify方法对应的是锁定的对象(这里是Test.object1)的方法
* notify的意思是:在执行完该同步代码块之后,唤醒一个调用了wait方法的线程并从wait处继续
* 执行wait方法下面的代码,如果没有调用notify方法,对应的线程将一直等待
*/
Test.object1.notify();
try {
Thread.sleep(10000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println("我是notify后面的代码,在notify后面所有代码执行完才会释放Test.object1的锁");
}
}
public void run() {
notifyTestMethod();
}
}
//对应的wait测试类,主要用于测试wait和notify之间的关系
class WaitNotifyTestDemo implements Runnable{
public static void waitNotifyMethod(){
synchronized (Test.object1) {
System.out.println("即将执行wait方法");
try {
/*这里执行了wait方法后,线程进入等待状态,释放锁,此时该锁被执行了notifyTestMethod方法线程获得
* 这里需要注意的是:该线程调用了wait方法之后,将一直等待直到notify方法或者notifyAll唤醒它
*/
Test.object1.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("我是wait后面的代码,我需要被外部线程的notify方法唤醒才能继续执行,否则,我所在线程是无法继续执行的,它将会一直处于等待状态!");
}
} public void run() {
waitNotifyMethod();
}
}

代码比较长,不过很多问题注释中也说清楚了,下面在进行简单的总结吧:

notify方法就是一个可以唤醒处于wait状态的线程的方法,至于唤醒的是哪个线程,一般是等待队列中的首个线程(这里补充下:线程调用了wait方法会自动被放进一个等待队列中的),然后该线程接着从wait代码块之后继续往下执行。

然后,这里再讲讲notifyAll的方法,notifyAll方法和notify方法大体上性质差不多,只是notifyAll方法表示唤醒wait队列中的所有线程,让这些线程进行锁的抢夺,谁抢到了,谁就拥有执行权,其他线程进入阻塞状态。

今天这篇博客代码量有点多,但是我发觉,多线程的东西,不用代码例子是难以理解的,最重要的是自己敲代码试试,这样学习效果比较明显,之前一直在看书,效果的确比不上代码中实验来得直观和易于理解。

java线程总结2--wait/notify(all)/sleep以及中断概念的更多相关文章

  1. Java线程通信——wait() 和 notify()

    Object类中有关线程通信的方法有两个notify方法和三个wait方法,官方解释: void notify() Wakes up a single thread that is waiting o ...

  2. java 线程之间通信以及notify与notifyAll区别。

    jvm多个线程间的通信是通过 线程的锁.条件语句.以及wait().notify()/notifyAll组成. 下面来实现一个启用多个线程来循环的输出两个不同的语句. package com.app. ...

  3. java——线程的wait()和notify()

    这是一个关于生产者和消费者的线程通信的例子: package thread_test; public class PCThread { public static void main(String[] ...

  4. JAVA 线程状态以及synchronized,wait,sleep,yield,notify,notifyAll

    java线程存在以下几种状态: 1: 创建状态(New):线程被new出来,还未调用start 2: 就绪状态(Runnable):又称为可执行状态,调用线程的start方法后,线程处于就绪状态,,线 ...

  5. java线程中的sleep/wait/notify/yield/interrupt方法 整理

    java线程中的sleep/wait/notify/yield/interrupt方法 sleep 该方法能够使当前线程休眠一段时间 休眠期间,不释放锁 休眠时间结束之后,进入可执行状态,加入到线程就 ...

  6. (删)Java线程同步实现一:synchronzied和wait()/notify()

    上面文章(2.Java多线程总结系列:Java的线程控制实现)讲到了如何对线程进行控制,其中有一个是线程同步问题.下面我们先来看一个例子: 1.一个典型的Java线程安全例子 package com. ...

  7. 【java线程系列】java线程系列之线程间的交互wait()/notify()/notifyAll()及生产者与消费者模型

    关于线程,博主写过java线程详解基本上把java线程的基础知识都讲解到位了,但是那还远远不够,多线程的存在就是为了让多个线程去协作来完成某一具体任务,比如生产者与消费者模型,因此了解线程间的协作是非 ...

  8. 【Java 线程的深入研究3】最简单实例说明wait、notify、notifyAll的使用方法

    wait().notify().notifyAll()是三个定义在Object类里的方法,可以用来控制线程的状态. 这三个方法最终调用的都是jvm级的native方法.随着jvm运行平台的不同可能有些 ...

  9. Java多线程:线程状态以及wait(), notify(), notifyAll()

    一. 线程状态类型1. 新建状态(New):新创建了一个线程对象.2. 就绪状态(Runnable):线程对象创建后,其他线程调用了该对象的start()方法.该状态的线程位于可运行线程池中,变得可运 ...

随机推荐

  1. 深入了解java虚拟机(JVM) 第八章 常见的jvm调优策略

    一般来说,jvm的调优策略是没有一种固定的方法,只有依靠我们的知识和经验来对项目中出现的问题进行分析,正如吉德林法则那样当你已经把问题清楚写出来,就已经解决了一半.虽然JVM调优中没有固定的策略,但是 ...

  2. 【ocp-12c】最新Oracle OCP-071考试题库(45题)

    45.(9-16)choose the best answer: View the Exhibit and examine the data in the EMPLOYEES table. You w ...

  3. spring-mybatis源码追踪

    启用一个扫描类 <bean class="org.mybatis.spring.mapper.MapperScannerConfigurer"> <propert ...

  4. Github 升级到 Rails 5.2.1 了

    简评:之前用的可是 3.2,早就该升级了啊. Github 的 Rails 升级花了大约一年半的时间,这是有原因的,首先,Rails 本身的升级并不总是平滑的,有些版本有重大改变(breaking c ...

  5. Ionic2 自学须知的基本知识点

    http://www.cnblogs.com/zsl123/p/5991336.html Ionic(ionicframework)一款接近原生的HTML5移动App开发框架. IONIC 是目前最有 ...

  6. java内存的分配策略

    1.概述 本文是<深入理解java虚拟机>(周志明著)3.6节的笔记整理,文章结构也与书上相同,讲述的是几条最普遍的内存分配策略. 2.对象优先在Eden分配 ** 大多数情况下,对象在新 ...

  7. 【笔记】AJAX基础

    [笔记]AJAX基础 Django AJAX  知识储备:JSON 什么是 JSON JSON 是轻量级的文本数据交换格式 JSON 独立于语言和平台.JSON 解析器和 JSON 库支持许多不同的编 ...

  8. 【算法笔记】A1039 Course List for Student

    https://pintia.cn/problem-sets/994805342720868352/problems/994805447855292416 题意: 有N个学生,K节课.给出选择每门课的 ...

  9. P3440 [POI2006]SZK-Schools

    传送门 应该是很显然的费用流模型吧... $S$ 向所有学校连边,流量为 $1$,费用为 $0$(表示每个学校要选一个编号) 学校向范围内的数字连边,流量为 $1$,费用为 $c|m-m'|$(表示学 ...

  10. springcloud(六)-Ribbon配置自定义算法

    前言 很多场景下,可能根据需要自定义Ribbon的配置,例如修改Ribbon的负载均衡规则等.Spring Cloud Edgware允许使用java代码或属性自定义Ribbon 的配置,两种方式等价 ...