`

Java多线程机制总结

    博客分类:
  • Java
 
阅读更多
程序、进程和线程:
程序是一段静态的代码,它是应用程序执行的蓝本。进程是程序的一次动态执行过程,它对应了从代码加载、执行至执行完毕的一个完整过程,这个过程也是进程本身从产生、发展至消亡的过程。线程是比进程更小的单位,一个进程执行过程中可以产生多个线程,每个线程有自身的产生、存在和消亡的过程,也是一个动态的概念。每个进程都有一段专用的内存区域,而线程间可以共享相同的内存区域(包括代码和数据),并利用这些共享单元来实现数据交换、实时通信与必要的同步操作。

每个Java程序都有一个默认的主线程。Java程序总是从主类的main方法开始执行。当JVM加载代码,发现main方法后就启动一个线程,这个线程就称作"主线程",该线程负责执行main方法。在main方法中再创建的线程就是其他线程。

如果main方法中没有创建其他线程,那么当main方法返回时JVM就会结束Java应用程序。但如果main方法中创建了其他线程,那么JVM就要在主线程和其他线程之间轮流切换,保证每个线程都有机会使用CPU资源,main方法返回(主线程结束)JVM也不会结束,要一直等到该程序所有线程全部结束才结束Java程序(另外一种情况是:程序中调用了Runtime类的exit方法,并且安全管理器允许退出操作发生。这时JVM也会结束该程序)。


线程的状态与生命周期:
Java使用java.lang.Thread类及其子类的对象表示线程,新建的线程在它的一个完整生命周期中通常要经历如下四种状态:(新建、运行、(中断/挂起/阻塞)、消亡)
1、新建:
当一个Thread类或其子类对象被声明并创建,新生的线程对象就处于新建状态(此时它已经有了内存空间和其他资源)。

2、运行:
线程已经创建就具备了运行的条件,一旦轮到它来享用CPU资源时,即JVM将CPU使用权切换给该线程时,此线程就可以脱离创建它的主线程独立开始自己的生命周期了。
线程创建后仅仅是占有了内存资源,在JVM管理的线程中还没有这个线程,此线程必须调用start()方法(从父类继承)通知JVM,这样JVM就知道又有一个新的线程排队等候切换。

当JVM将CPU使用权切换给线程时,如果线程是Thread的子类创建的,该类中的run()方法立刻执行(run()方法中规定了该线程的具体使命)。Thread类中的run()方法没有具体内容,程序要在Thread类的子类中重写run()方法覆盖父类该方法。(注意:在线程没有结束run()方法前,不要再调用start方法,否则将发生ILLegalThreadStateException异常)

3、挂起:
线程挂起的原因有一下四种:
(1)、JVM将CPU资源从当前线程切换给其他线程,使本线程让出CPU的使用权,并处于挂起状态。
(2)、线程使用CPU资源期间,执行了sleep(int millsecond)方法,使当前线程进入休眠状态。sleep(int millsecond)方法是Thread类中的一个类方法,线程执行该方法就立刻让出CPU使用权,进入挂起状态。经过参数millsecond指定的毫秒数之后,该线程就重新进到线程队列中排队等待CPU资源,然后从中断处继续运行。
(3)、线程使用CPU资源期间,执行了wait()方法,使得当前线程进入等待状态。等待状态的线程不会主动进入线程队列等待CPU资源,必须由其他线程调用notify()方法通知它,才能让该线程从新进入到线程队列中排队等待CPU资源,以便从中断处继续运行。
(4)、线程使用CPU资源期间,执行某个操作进入阻塞状态,如执行读/写操作引起阻塞。进入阻塞状态时线程不能进入线程队列,只有引起阻塞的原因消除时,线程才能进入到线程队列排队等待CPU资源,以便从中断处继续运行。

4、死亡:
死亡状态就是线程释放了实体,即释放了分配给线程对象的内存。线程死亡的原因有两个:
(1)、正常运行的线程完成了它的全部工作,即执行完run()方法中的全部语句,结束了run()方法。
(2)、线程被提前强制性终止,即强制run()方法结束。


线程调度与优先级:
JVM的线程调度器负责管理线程,调度器把线程的优先级分为10个级别,分别用Thread类中的类常量表示。每个Java线程的优先级都在常数1-10之间。Thread类优先级常量有三个:
  static int MIN_PRIORITY  //1
  static int NORM_PRIORITY //5
  static int MAX_PRIORITY  //10
如果没有明确设置,默认线程优先级为常数5即Thread.NORM_PRIORITY。

线程优先级可以用setPriority(int grade)方法调整,如果参数grade不在1-10范围内,那么setPriority产生一个IllegalArgumenException异常。用getPriority()方法返回线程优先级。(注意:有些操作系统只能识别3个级别:1、5、10)

Java调度器的任务是使优先级高的线程能始终运行,一旦时间片有空闲,则使具有同等优先级的线程以轮流的方式顺序使用时间片。只有当高级别的线程死亡时(除非用sleep(int millsecond)或wait()方法让出CPU资源),低级别线程才有机会获得CPU资源。

实际编程时,不提倡使用线程的优先级来保证算法的正确执行。要编写正确、跨平台的多线程代码,必须假设线程在任何时刻都有可能被剥夺CPU资源的使用权。


Java中实现多线程有两种方法:
1、继承Thread类,覆盖run()方法:使用Thread子类创建线程的优点是可以在子类中增加新的成员变量或方法,使线程具有某种属性或功能。但Java不支持多继承,Thread类的子类不能再扩展其他的类。
2、实现Runnable接口:用Thread类直接创建线程对象,使用构造函数Thread(Runnable target)(参数target是一个Runnable接口),创建线程对象时必须向构造方法参数传递一个实现Runnable接口类的实例,该实例对象称作所创线程的目标对象。当线程调用start()方法,一旦轮到它使用CPU资源,目标对象自动调用接口中的run()方法(接口回调)。

线程间可以共享相同的内存单元(包括代码和数据),并利用这些共享单元来实现数据交换、实时通信与必要的同步操作。对于Thread(Runnable target)创建的使用同一目标对象的线程,可以共享该目标对象的成员变量和方法。
另外,创建目标对象类在必要时还可以是某个特定类的子类,因此,使用Runnable接口比使用Thread的子类更具有灵活性。
(注意:具有相同目标对象的线程,run()方法中的局部变量相互独立,互不干扰)

在线程中启动其他线程,当线程调用start()方法启动,使之从新建态进入就绪队列,一旦得到CPU资源就脱离创建它的主线程,开始自己的生命周期。


线程的常用方法:
start():线程调用该方法将启动线程,从新建态进入就绪队列,一旦享用CPU资源就可以脱离创建它的线程,独立开始自己的生命周期。

run():Thread类的run()方法与Runnable接口中的run()方法功能和作用相同,都用来定义线程对象被调度后所进行的操作,都是系统自动调用而用户不得引用的方法。run()方法执行完毕,线程就成死亡状态,即线程释放了分配给它的内存(死亡态线程不能再调用start()方法)。在线程没有结束run()方法前,不能让线程再调用start()方法,否则将发生IllegalThreadStateException异常。

sleep(int millsecond):有时,优先级高的线程需要优先级低的线程做一些工作来配合它,此时为让优先级高的线程让出CPU资源,使得优先级低的线程有机会运行,可以使用sleep(int millsecond)方法。线程在休眠时被打断,JVM就抛出InterruptedException异常。因此,必须在try-catch语句块中调用sleep方法。

isAlive():当线程调用start()方法并占有CPU资源后该线程的run()方法开始运行,在run()方法没有结束之前调用isAlive()返回true,当线程处于新建态或死亡态时调用isAlive()返回false。
注意:一个已经运行的线程在没有进入死亡态时,不要再给它分配实体,由于线程只能引用最后分配的实体,先前的实体就成为了"垃圾",并且不能被垃圾回收机制收集。

currentThread():是Thread类的类方法,可以用类名调用,返回当前正在使用CPU资源的线程。

interrupt():当线程调用sleep()方法处于休眠状态,一个占有CPU资源的线程可以让休眠的线程调用interrupt()方法"吵醒"自己,即导致线程发生IllegalThreadStateException异常,从而结束休眠,重新排队等待CPU资源。


GUI线程:JVM在运行包含图形界面应用程序时,会自动启动更多线程,其中有两个重要的线程:AWT-EventQueue和AWT-Windows。AWT-EventQueue线程负责处理GUI事件,AWT-Windows线程负责将窗体或组件绘制到桌面。


线程同步:(用synchronized修饰某个方法,该方法修改需要同步的变量;或用volatile修饰基本变量)
当两个或多个线程同时访问一个变量,并且一个线程需要修改这个变量时,应对这样的问题进行处理,否则可能发生混乱。

要处理线程同步,可以把修改数据的方法用关键字synchronized修饰。一个方法使用synchronized修饰,当一个线程A使用这个方法时,其他线程想使用该方法时就必须等待,直到线程A使用完该方法。所谓同步就是多个线程都需要使用一个synchronized修饰的方法。

volatile比同步简单,只适合于控制对基本变量(整数、布尔变量等)的单个实例的访问。java中的volatile关键字与C++中一样,用volatile修饰的变量在读写操作时不会进行优化(取cache里的值以提高io速度),而是直接对主存进行操作,这表示所有线程在任何时候看到的volatile变量值都相同。


在同步方法中使用wait()、notify()、notifyAll()方法:
当一个线程使用的同步方法中用到某个变量,而此变量又需要其他线程修改后才能符合本线程需要,那么可以在同步方法中使用wait()方法。中断方法的执行,使本线程等待,暂时让出CPU资源,并允许其他线程使用这个同步方法。其他线程如果在使用这个同步方法时不需要等待,那么它使用完这个同步方法时应当用notifyAll()方法通知所有由于使用这个同步方法而处于等待的线程结束等待。曾中断的线程就会从中断处继续执行,并遵循"先中断先继续"的原则。如果用的notify()方法,那么只是通知等待中的线程中某一个结束等待。


计时器线程Timer:(Timer还有很多高级操作,详细见JDK,这里做个概述)
java.swing.Timer类用于周期性地执行某些操作。有两个常用构造函数
public Timer(int delay, ActionListener listener):参数listener是计时器的监视器,计时器发生振铃的事件是ActionEvent类型事件,当振铃事件发生,监视器会监视到这个事件并回调ActionListener接口中的actionPerformed(ActionEvent e)方法。

public Timer(int delay):使用该构造方法,计时器要再调用addActionListener(ActionListener listener)方法获得监视器。

如果想让计时器只震动一次,可以让计时器调用setRepeats(boolean b)方法,参数b取false即可。
计时器还可以调用setInitialDelay(int delay)方法设置首次振铃的延时,如果没有设置首次振铃默认延时为构造函数中的参数delay。
还可以调用getDelay()和setDelay(int delay)获取和设置延时。
计时器创建后调用start()启动,调用stop()停止,即挂起,调用restart()重新启动计时器,即恢复线程。


线程联合:
一个线程A在占有CPU资源期间,可以让其他线程调用join()方法和本线程联合,如:
  B.join();
此时称A在运行期间联合了B。这时A线程立刻终端执行,一直等到它联合的线程B执行完毕,A线程再重新排队等待CPU资源。但如果A准备联合的线程B已经结束,则B.join()不会产生任何效果。


守护线程:
线程默认是非守护线程,非守护线程也称用户线程,一个线程调用setDaemon(boolean on)方法可以将自己设置成一个守护(Daemon)线程,如:
  thread.setDaemon(true);
一个线程必须在自己运行之前设置自己是否是守护线程。守护线程是当程序中所有用户线程都已结束运行时即使守护线程的run()方法还有需要执行的语句,守护线程也会立刻结束运行。因此守护线程用于做一些不是很严格的工作,当线程随时结束时不会产生什么不良后果。

原文:http://blog.csdn.net/lj70024/article/details/5455790
分享到:
评论

相关推荐

    Java多线程知识点总结

    Java多线程是Java编程语言中一个非常重要的概念,它允许开发者在一个程序中创建多个执行线程并行运行,以提高程序的执行效率和响应速度。...在实际开发中,正确地应用多线程机制可以显著提升程序的性能和用户体验。

    Java多线程编程总结

    ### Java多线程编程总结 #### 一、Java线程:概念与原理 1. **操作系统中线程和进程的概念** - 当前的操作系统通常为多任务操作系统,多线程是实现多任务的一种手段。 - **进程**:指内存中运行的应用程序,每个...

    Java多线程的总结

    Java多线程是Java编程中的一个核心概念,它在现代软件开发中扮演着至关重要的角色。多线程允许程序同时执行多个任务,提高了系统资源的利用率,提升了应用程序的响应速度和并发性能。对于大型分布式系统、Web应用...

    java多线程编程总结

    ### Java多线程编程总结 #### 一、Java线程:概念与原理 - **操作系统中线程和进程的概念** 当前的操作系统通常都是多任务操作系统,多线程是一种实现多任务的方式之一。在操作系统层面,进程指的是内存中运行的...

    40个Java多线程问题总结

    ### Java多线程问题总结 #### 一、多线程的作用与优势 1. **发挥多核CPU的优势:** - 当今计算机硬件普遍配备有多核CPU,利用多线程技术能够有效地分配任务到不同的核心上,使得计算资源得到最大化利用。在双核...

    JAVA多线程机制

    Java多线程机制是Java编程中的重要组成...总结来说,Java多线程机制为我们提供了丰富的手段来实现并发编程,包括线程的创建、线程同步和线程安全。理解和掌握这些知识,能够帮助开发者构建高效、可靠的多线程应用程序。

    java多线程分页查询

    ### Java多线程分页查询知识点详解 #### 一、背景与需求分析 在实际的软件开发过程中,尤其是在处理大量数据时,如何高效地进行数据查询成为了一个关键问题。例如,在一个用户众多的社交平台上,当用户需要查看...

    JAVA多线程编程技术PDF

    总结起来,“JAVA多线程编程技术PDF”涵盖了多线程的基本概念、同步机制、线程通信、死锁避免、线程池以及线程安全的集合类等内容。通过深入学习这份资料,开发者可以全面掌握Java多线程编程技术,提升程序的并发...

    Java 多线程学习总结6

    在“Java多线程学习总结6”这个主题中,我们可以深入探讨Java多线程的实现、管理及优化。下面将详细阐述相关知识点。 1. **线程的创建方式** - **继承Thread类**:自定义类继承Thread类,并重写run()方法,创建...

    JAVA教程解析Java的多线程机制

    总结来说,Java的多线程机制为开发者提供了强大的工具来构建高效、响应迅速的应用程序。通过对进程与线程的理解,以及掌握Java中实现多线程的不同方法,开发者可以更好地利用现代多核处理器的优势,优化应用程序的...

    我总结的Java多线程程序设计

    Java多线程程序设计是Java开发中的重要组成部分,它允许程序在同一时间执行多个任务,从而提高了系统的效率和响应性。本文将深入探讨Java多线程的相关概念和实现方式。 一、理解多线程 1. **线程定义**:线程是一...

    实验八:Java多线程

    ### 实验八:Java多线程 #### 一、实验目的与知识点概述 在本实验中,我们将深入了解线程与进程的基本概念、它们之间的区别与联系,并掌握多线程技术在Java中的应用方法。具体包括以下几点: 1. **线程与进程的...

    java多线程.pdf

    ### Java多线程知识点详解 #### 一、Java多线程概述 **Java多线程**是指在Java程序中能够同时执行多个线程的技术。这种技术使得程序可以在多个任务之间并发执行,从而提高了程序的效率和资源利用率。本文将根据...

    java多线程设计

    总结,Java多线程设计是构建高性能、高并发应用的基础。通过理解并合理使用不可变对象,我们可以有效预防多线程环境中的非安全问题,确保程序的稳定性和正确性。在实际开发中,结合各种线程同步机制和并发工具,可以...

    java多线程之赛马程序实验8多线程练习下载进度

    总结来说,这个实验旨在帮助开发者深入理解Java多线程的概念,熟练运用`Thread`类的`run`和`start`方法,以及如何通过进度条来实时展示多线程任务的执行进度。通过实践,开发者可以更好地掌握并发编程的技巧,这对于...

    Java的多线程机制

    ### Java的多线程机制详解 #### 一、引言 随着计算机技术的快速发展,现代计算机系统的架构变得越来越复杂多样。然而,在当前的技术背景下,多线程编程模型被视为计算机系统架构的重要组成部分。随着CPU主频的提升...

    Java_多线程与并发编程总结.doc

    Java多线程与并发编程是Java开发中至关重要的一部分,它涉及到如何高效地利用CPU资源,以实现程序的并行执行。在操作系统层面,多任务和多进程是通过分配不同的内存空间来实现的,而线程则共享同一进程的内存,这...

    JAVA多线程总结

    【JAVA多线程总结】 Java 多线程是Java编程中的关键特性,它允许程序同时执行多个任务,提高系统的效率和响应性。本篇总结涵盖了Java多线程的基础概念、创建与启动、线程调度、同步与协作以及新特性。 **一、Java...

Global site tag (gtag.js) - Google Analytics