程序、进程和线程:
程序是一段静态的代码,它是应用程序执行的蓝本。进程是程序的一次动态执行过程,它对应了从代码加载、执行至执行完毕的一个完整过程,这个过程也是进程本身从产生、发展至消亡的过程。线程是比进程更小的单位,一个进程执行过程中可以产生多个线程,每个线程有自身的产生、存在和消亡的过程,也是一个动态的概念。每个进程都有一段专用的内存区域,而线程间可以共享相同的内存区域(包括代码和数据),并利用这些共享单元来实现数据交换、实时通信与必要的同步操作。
每个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()方法还有需要执行的语句,守护线程也会立刻结束运行。因此守护线程用于做一些不是很严格的工作,当线程随时结束时不会产生什么不良后果。
分享到:
相关推荐
Java多线程机制是Java编程中至关重要的一部分,它允许程序同时执行多个任务,提升应用程序的效率和响应性。以下是对各个知识点的详细说明: 9.1 Java中的线程: Java程序中的线程是在操作系统级别的线程基础上进行...
Java多线程机制是Java编程中的重要组成部分,它允许程序同时执行多个任务,极大地提高了程序的效率和响应性。在现代计算机系统中,多线程是实现并发处理的关键技术,尤其在服务器端应用和高性能计算中不可或缺。本文...
java多线程机制
### Java多线程机制详解与示例 #### 一、Java多线程机制概述 Java中的多线程机制是程序设计中的一个重要概念,它允许在同一个应用程序中并发执行多个线程,有效地提高了程序的执行效率和响应速度。通过Java语言...
当用户在“命令”后的文本框中输入“start clock”后,“现在的时间是”后的文本框开始显示系统时钟;当用户输入“stop clock”后,时钟终止显示。 (2)当用户在“命令”后的文本框中输入“fast”后,能够加速滚动...
基于Java多线程机制的龟兔赛跑程序 本文旨在介绍基于Java多线程机制的龟兔赛跑程序的设计和实现。首先,文章概述了Java语言的多线程机制的重要性和必要性,然后详细介绍了基于线程和基于进程的多线程机制的基本概念...
"Java多线程机制探讨" Java多线程机制是指在Java语言中实现多线程编程的机制。多线程机制允许多个线程同时执行,提高了程序的效率和响应速度。Java多线程机制可以通过Thread类或Runnable接口实现。 Thread类是Java...
Java多线程机制研究.kdh Java多线程机制研究.kdh Java多线程机制研究.kdh
"Java多线程机制详解" Java多线程机制是Java语言中的一种重要机制,能够提高程序的执行效率。本文将介绍Java语言中多线程的两种实现方式,并分别举例说明了各自的特点、格式以及运行结果。 第一种实现方式是实现...
### 基于Java多线程机制的探析 #### 摘要 本文深入探讨了Java多线程机制的基本原理及其应用场景。首先简要分析了Java多线程的概念及其实现方法,随后详细介绍了多线程在多用户远程协同工作系统中的应用,特别是...
Java多线程机制研究 Java多线程机制研究是Java编程语言的一项重要特点,允许在一个Java程序内部同时进行多种运算,从而充分利用系统资源,提高程序运行效率。本文将详细论述在Java程序中创建线程和实现线程体的机制...
Java多线程机制是编程中一个重要的概念,它允许程序同时执行多个任务,提升程序的效率和响应性。在Java中,线程是程序执行的基本单元,比进程更细粒度,一个进程可以包含多个线程。每个线程有自己的生命周期,包括...
### JAVA多线程机制在波形流动中的应用及分析 #### 摘要与引言 本文探讨了JAVA多线程机制在波形流动中的应用,并对其原理与实现方法进行了深入分析。首先简要介绍了JAVA语言的特点,特别是其内置的多线程支持,这...
Java的多线程机制是Java语言的一大特性,它允许程序同时执行多个任务,提升程序响应速度,优化资源利用率。在Java中,线程是程序执行的最小单位,一个进程可以包含多个线程,每个线程都有自己独立的生命周期,包括...
Java 多线程机制是Java语言的一大特性,它允许程序同时执行多个任务,模拟现实生活中的并发行为。在Java中,创建线程有两种主要方式:继承Thread类和实现Runnable接口。 在例子1中,我们看到一个简单的多线程示例。...
标题和描述中提到的“Java多线程机制及其在socket编程中的应用.pdf”,暗示了文章的两大核心内容:Java多线程技术和这些技术如何应用于socket编程。为了深入探讨这些内容,我们首先需要了解Java多线程的几个关键知识...
根据提供的文件信息,可以提炼出一系列关于Java多线程机制的知识点。以下知识点均围绕Java多线程展开,并详细解释涉及的概念和组件: 1. 多线程基础概念: - Java多线程是指在Java语言中能够同时执行多个线程的...
Java多线程机制是Java语言的一个重要特性,它允许程序同时执行多个任务,极大地提高了程序的效率和响应性。在Java中,实现多线程有两种主要方式:通过继承Thread类和实现Runnable接口。理解并掌握多线程机制是成为一...