`

java多线程基础知识——调度与同步

阅读更多

以前写过一篇关于多线程的总结: 
http://kyfxbl.iteye.com/blog/1370377 

很久没用到,忘记了。最近又遇到了一些多线程的问题,重新查了些资料,再提炼一下。本文不涉及java.util.concurrent包里的API,后面再专门介绍 

1、线程的状态 

线程的运行状态主要有runnable、running、waiting、timed_waiting、blocked等,主要有2类API,可以控制线程的运行状态 

第一类是调度类,不涉及object monitor和synchronized方法,这类API包括yield()、sleep()、join()等 

第二类是同步类,涉及到object monitor和synchronized方法,这类API包括wait()、notify()、notifyAll() 

总的来说,第一类API比第二类要简单 

2、调度类API 

这类API不涉及同步方法,是直接控制线程的运行状态,都是Thread类定义的方法 

yield()会使线程从running状态切换到runnable状态,但是也有可能JVM立刻又把该线程切换回running状态(优先级高、无其他线程等原因),可以说,这个方法只是“建议”jvm先去执行其他线程,运行结果是不能保证的 

sleep()需要跟一个参数,单位是毫秒,会使线程进入timed_waiting状态,sleep时间结束以后,会回到runnable状态 

join()使当前线程进入waiting状态,等join的线程执行完毕之后,才回到runnable状态。举例来说,有2个线程t1和t2,在t1里执行了t2.join(),则t1进入waiting状态,等t2执行完毕之后,t1才回到runnable状态 

Java代码  收藏代码
  1. public static void main(String[] args) throws InterruptedException {  
  2.   
  3.         final Thread thread = new Thread(new Runnable() {  
  4.   
  5.             @Override  
  6.             public void run() {  
  7.                 try {  
  8.                     Thread.sleep(10000);// 此行代码使该线程进入timed_waiting状态  
  9.                 } catch (InterruptedException e) {  
  10.                     e.printStackTrace();  
  11.                 }  
  12.             }  
  13.   
  14.         });  
  15.   
  16.         thread.start();  
  17.   
  18.         new Thread(new Runnable() {  
  19.   
  20.             @Override  
  21.             public void run() {  
  22.                 try {  
  23.                     thread.join();// 此行代码使该线程进入waiting状态,等待thread执行完毕  
  24.                 } catch (InterruptedException e) {  
  25.                     e.printStackTrace();  
  26.                 }  
  27.             }  
  28.   
  29.         }).start();  
  30.   
  31.     }  


用jstack看到这2个线程的状态: 

 

Thread-0由于执行了sleep()方法,而进入timed_waiting状态;Thread-1由于执行了join()方法,而进入waiting状态 

调度类的API不涉及synchronized方法,所以也不涉及到blocked状态 

3、synchronized关键字与object monitor 

同步的关键字是synchronized,其实我觉得叫“锁定”会比较好,不知道怎么理解“同步”这个词 

synchronized方法包括2种,一种是标注了synchronized关键字的方法,一种是synchronized代码块 

本质上差不多,只要是同步方法,都有一个object monitor:对于synchronized关键字方法来说,monitor就是该方法所属的类的实例;对于synchronized代码块来说,monitor是在synchronized关键字后面直接指定的 

当线程执行到同步方法或者同步代码块的时候,就会获取object monitor,并继续执行;但是,同一时刻,只有唯一一个线程可以获取object monitor,其他的线程就会阻塞,进入blocked状态,等待持有object monitor的那个线程释放object monitor 

这就是同步代码的基本状况,如果没有同步类的API的话,多线程执行就无法控制了,只能线程A获取->线程A释放->线程B获取->线程B释放->线程C获取……,这样顺序执行下去,所以就有了下面的同步类API 

4、同步类API 

前面说到了,同步的代码(方法或代码块),都有一个object monitor,可以通过在object monitor上执行wait()、notify()、notifyAll()方法,来进行多线程之间的通信 

在object monitor上执行wait()方法,会使当前的线程释放锁,并进入waiting状态;并将该线程加入object monitor内部的“等待线程列表”中 

在object monitor上执行notify()方法,会从“等待线程列表”中随机挑选一个线程唤醒,进入runnable状态(如果没有获取object monitor,则会立刻进入blocked状态) 

在object monitor上执行notifyAll()方法,会将“等待线程列表”中所有的线程都唤醒,全部进入runnable状态(但是随后没有获取object monitor的线程,会立刻进入blocked状态) 

注意,当一个线程调用了object.wait()方法进入waiting状态之后,如果没有其他线程帮它调用object.notify()方法,则该线程将永远停留在waiting状态,此线程永不结束 

贴一段示例代码进行说明: 

Java代码  收藏代码
  1. public static void main(String[] args) {  
  2.   
  3.         final Object o = new Object();  
  4.   
  5.         new Thread(new Runnable() {  
  6.   
  7.             @Override  
  8.             public void run() {  
  9.                 synchronized (o) {  
  10.                     try {  
  11.                         System.out.println("me first");// 这个线程先执行,是期望的结果,但是不能保证  
  12.                         Thread.sleep(15000);  
  13.                         o.wait();  
  14.                         System.out.println("wake up and done");  
  15.                     } catch (InterruptedException e) {  
  16.                         e.printStackTrace();  
  17.                     }  
  18.                 }  
  19.             }  
  20.   
  21.         }).start();  
  22.   
  23.         new Thread(new Runnable() {  
  24.   
  25.             @Override  
  26.             public void run() {  
  27.                 synchronized (o) {  
  28.                     try {  
  29.                         System.out.println("it's my time");// 如果这个线程先执行,则另一个线程将永远waiting  
  30.                         Thread.sleep(15000);  
  31.                         o.notify();  
  32.                     } catch (InterruptedException e) {  
  33.                         e.printStackTrace();  
  34.                     }  
  35.                 }  
  36.             }  
  37.   
  38.         }).start();  
  39.   
  40.     }  


阶段1:thread-0进入timed_waiting状态,thread-1没有获取到object monitor,进入blocked状态 

 

控制台输出:me first 

阶段2:thread-0调用了o.wait()方法,释放锁并进入waiting状态;thread-1执行sleep()方法,进入timed_waiting状态 

 

控制台输出:it's my time 

阶段3:thread-1执行o.notify()方法,唤醒thread-0,自己运行结束,释放锁(并不是notify方法释放了锁);thread-0执行最后一行代码,然后也结束;两个线程都执行完毕 

控制台输出:wake up and done 

但是,这里有很强的随机性,每次执行的效果是不同的!如果是thread-1先执行的话,那么当thread-0调用o.wait()之后,就会永远停留在waiting状态,该线程永远不会结束 

5、同步类API的限制 

上述3个方法,都是只能在synchronized代码里调用的,否则就会报错。也就是说,虽然这3个方法都是Object类定义的方法,但是只有成为object monitor的实例才能调用 

比如以下这段代码是不能执行的,o是object monitor,而o1不是,所以不能调用o1.wait(): 

Java代码  收藏代码
  1. public static void main(String[] args) {  
  2.   
  3.         final Object o = new Object();  
  4.   
  5.         final Object o1 = new Object();  
  6.   
  7.         new Thread(new Runnable() {  
  8.   
  9.             @Override  
  10.             public void run() {  
  11.   
  12.                 synchronized (o) {  
  13.                     try {  
  14.                         o1.wait();// 错误  
  15.                     } catch (InterruptedException e) {  
  16.                         e.printStackTrace();  
  17.                     }  
  18.                 }  
  19.   
  20.             }  
  21.   
  22.         }).start();  
  23.   
  24.     }  



6、总结 

yield()、sleep()、join()都是Thread类定义的方法,不涉及同步方法,因此也不会使线程切换到blocked状态,也不涉及object monitor的释放 

wait()、notify()、notifyAll()是Object类定义的方法,但是只能在object monitor实例上调用 

wait()方法会立刻释放object monitor,并使当前线程进入waiting状态 

notify()和notifyAll()方法只是唤醒此前调用了wait()方法的线程,但是自己并不会释放锁 

本文也参考了: 
http://dylanxu.iteye.com/blog/1322066

 

转自:http://www.iteye.com/topic/1129528

分享到:
评论

相关推荐

    java多线程案例——未完成

    下面是对Java多线程基础知识的详细解释: 1. **线程的创建方式**: - 继承`Thread`类:自定义一个新的类,继承Java的`Thread`类,并重写`run()`方法。创建实例后调用`start()`方法启动线程。 - 实现`Runnable`...

    Java线程基础知识

    总结来说,Java线程基础知识涵盖的内容丰富,从线程的基本概念,到线程在程序中的应用,再到线程间的通信和同步机制,都是多线程编程中不可或缺的一部分。掌握这些知识对于开发高性能、多任务并行处理的应用程序具有...

    java多媒体与多线程处理实验

    ### Java多媒体与多线程...通过本次实验,学生不仅掌握了Java多线程编程的基础知识,还学会了如何利用多线程优化程序性能,特别是在多媒体应用领域,如动画、音视频处理等,为后续更复杂的应用开发奠定了坚实的基础。

    Java多线程

    Java多线程知识点梳理: 1. Java线程基础知识 - 线程是程序中独立的、并发的执行路径。每个线程都有自己的堆栈、程序计数器和局部变量,但与分隔的进程不同,线程之间的隔离程度较小,它们共享内存、文件句柄等...

    java多线程学习资料

    ### Java多线程学习资料知识点解析 #### 一、引言 Java作为一种广泛使用的编程语言,在并发编程领域具有独特的优势。多线程是Java中实现并发处理的核心技术之一,能够显著提升程序的性能和响应性。本文将深入探讨...

    Java多线程入门介绍.pdf

    本文将详细介绍Java多线程的基础知识,包括线程的概念、线程的生命周期、线程的同步机制、线程之间的数据传递以及如何在Java中创建和管理线程。 #### 二、进程与线程的概念 在深入探讨Java多线程之前,我们先来...

    java常用的代码——线程

    ### Java中的线程基础 #### 1. 什么是线程? 在计算机科学中,线程是指进程中的一个执行单元,它是进程内部的基本调度单位。与进程相比,线程是轻量级的进程,因为它复用了进程的资源(如内存空间),因此创建和...

    经典线程例子——Java线程学习指南

    一、Java线程基础知识 在Java中,线程是程序中的单一顺序控制流程。一个进程可以包含多个线程,每个线程都有自己的程序计数器、虚拟机栈、本地方法栈和一部分堆内存。Java提供了两种创建线程的方式: 1. 继承Thread...

    smoker_java多线程_

    总之,Java多线程编程是构建高效并发应用的基础,涵盖了许多概念和技术,如线程的创建与管理、同步机制、线程安全的数据访问以及线程间通信。理解并熟练掌握这些知识点对于任何Java开发者来说都是至关重要的。

    Java多线程与并发库高级应用

    #### 一、Java多线程基础 在深入探讨Java多线程与并发库的高级应用之前,我们首先需要回顾一下Java多线程的基础概念和技术要点。 ##### 1.1 线程的概念 在计算机科学中,线程是操作系统能够进行运算调度的最小...

    多线程 Java 原创作品

    这个“多线程 Java 原创作品”展示了Java多线程技术在实际应用中的一个实例,不仅涉及了多线程的基础知识,还可能涵盖了高级特性和技巧,如线程同步、音乐播放等,是一个全面的多线程实践案例。通过学习和分析这个...

    Java线程-第三版(CHM电子版)

    《Java线程——第三版》是一本专注于Java多线程编程的专业书籍,旨在帮助开发者深入理解和熟练掌握Java中的并发处理技术。多线程是现代软件开发中的重要概念,尤其是在服务器端应用、分布式系统以及高性能计算等领域...

    中山大学研究生学院java讲义之(多线程)

    综上所述,中山大学研究生学院的Java多线程课程涵盖了多线程编程的关键知识点,从基础到高级,为学生提供了全面的并发编程理论和实践指导。通过学习这些内容,学生可以更好地理解和解决实际开发中的并发问题。

    第13章龟兔赛跑——多线程.ppt

    总结来说,通过学习"第13章龟兔赛跑——多线程",我们可以掌握Java中多线程的基本概念、创建和管理,以及如何利用多线程提高程序效率。理解并熟练应用这些知识对于开发高效、响应迅速的软件至关重要。

    java十大经典案例——时钟显示

    1. **Java多线程基础**: Java提供两种方式创建线程:继承`Thread`类或实现`Runnable`接口。在这个时钟显示案例中,我们可能会看到`Runnable`接口的使用,因为这样可以避免单继承的限制,更容易地实现代码复用。 2...

    java线程入门 Java线程编程很好的入门书

    通过上述内容,我们可以看到Java线程编程涵盖了许多方面,从基础知识到高级应用,每个主题都值得深入研究。在实际开发中,理解和熟练运用这些知识,能帮助我们编写出更加高效、稳定的多线程程序。

    Java SE完整版精品优质课件 自学入门必看的优秀Java基础知识培训教案 第11章_多线程(共54页).rar

    总结来说,本课件《Java SE完整版精品优质课件 自学入门必看的优秀Java基础知识培训教案 第11章_多线程》将深入探讨Java中的多线程编程,包括线程的创建、管理、同步、通信以及异常处理等方面,帮助初学者掌握这一...

    并发编程——线程基础.pdf

    总的来说,Java中的并发编程是一门综合技术,它涉及对线程生命周期的理解、线程间通信与协作、线程同步以及并发控制等多方面知识。通过学习并发编程,可以增强处理多任务的能力,提高程序的响应性和吞吐量。这对于...

    java线程实战手册

    《Java线程实战手册》是Java并发编程领域的一份重要参考资料,主要针对Java开发者,旨在帮助他们深入理解和熟练掌握Java中的多线程技术。虽然这里只提供了第一章的内容,但这一章通常会涵盖基础理论和核心概念,对于...

    java线程基础讲解

    ### Java线程基础详解 #### 一、线程概述 **1.1 什么是线程?** 线程是操作系统能够进行运算调度的最小单位,它被包含在进程之中,是进程中的实际运作单位。在Java中,线程是程序执行流的最小单元,一个标准的...

Global site tag (gtag.js) - Google Analytics