上一篇关于线程的博客简单梳理了一下多线程的一些基本概念,今天这篇博客再进行多线程编程中一些核心的方法进行简单的梳理和总结,主要是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. Python面向对象(定义类和创建对象)

    day24 http://www.cnblogs.com/wupeiqi/p/4493506.html Python:函数式+面向对象,函数式编程可以做所有事,但是不一定合适. 小明,10岁,男,上山 ...

  2. 工作中遇到的两个问题-正则以及console

    一.今天做点击按钮验证邮箱时,遇到以下几个问题: (1)点击按钮后,执行if(regExp.test(str)),出现一种奇怪的现象:第一次输入正确邮箱验证通过,第二次输入正确邮箱就返回false,第 ...

  3. tf.nn.conv2d()需要搞清楚的几个变量。

    惯例先展示函数: tf.nn.conv2d(input, filter, strides, padding, use_cudnn_on_gpu=None, name=None) 除去name参数用以指 ...

  4. python os用法详解

    前言:在自动化测试中,经常需要查找操作文件,比如说查找配置文件(从而读取配置文件的信息),查找测试报告(从而发送测试报告邮件),经常要对大量文件和大量路径进行操作,这就依赖于os模块,所以今天整理下比 ...

  5. Tomcat启动和请求处理解析

    tomcat是我们经常使用的组件,但是内部是如何运行的呢,我们去一探究竟. 1.tomcat架构 tomcat的整体架构图如下: Tomcat中只有一个Server,一个Server可以有多个Serv ...

  6. Postgres中的SpinLock锁

    我们知道,在数据库中为了并发控制,少不了要使用各种各样的锁(lock).PostgreSQL中也不例外. 在PostgreSQL中有三种级别的锁,他们的关系如下: |上层 RegularLock | ...

  7. J2SE基本安装和java的环境变量

    J2SE基本安装和java的环境变量   1. 首先登录http://www.oracle.com,下载JDK(J2SE) JDK有很多版本其中JDK 1.0,1.1,1.2,1.3,1.4 1.5 ...

  8. ORACLE 动态执行SQL语句

    本文转自 http://zhaisx.iteye.com/blog/856472 Oracle 动态SQL Oracle 动态SQL有两种写法:用 DBMS_SQL 或 execute immedia ...

  9. mysql工具——mysqlcheck(MYISAM)

    基本介绍 演示: 使用optimize的时候,可能会出现 Table does not support optimize, doing recreate + analyze instead 这时候参考 ...

  10. main:处理命令行选项

    有时我们需要给main函数传递实参, 我们可以把命令行选项通过两个形参传递给main函数: int mian(int argc, char *argv[]) { ... }; argv是argumen ...