java多线程与并发之java线程简介(二)
2011-09-13 16:36
302 查看
线程的生命
----------
创建线程
在 Java 程序中创建线程有几种方法。每个 Java 程序至少包含一个线程:主线程。其它线程都是通过 Thread 构造器或实例化继承类 Thread 的类来创建的。当我们讨论 Java 程序中的线程时,也许会提到两个相关实体:完成工作的实际线程或代表线程的 Thread 对象。正在运行的线程通常是由操作系统创建的;Thread 对象是由 Java VM 创建的,作为控制相关线程的一种方式。
创建线程和启动线程并不相同
在一个线程对新线程的 Thread 对象调用 start() 方法之前,这个新线程并没有真正开始执行。Thread 对象在其线程真正启动之前就已经存在了,而且其线程退出之后仍然存在。这可以让您控制或获取关于已创建的线程的信息,即使线程还没有启动或已经完成了。
通常在构造器中通过 start() 启动线程并不是好主意。这样做,会把部分构造的对象暴露给新的线程。如果对象拥有一个线程,那么它应该提供一个启动该线程的 start() 或 init() 方法,而不是从构造器中启动它。
结束线程
线程会以以下三种方式之一结束:
1.线程到达其 run() 方法的末尾。
2.线程抛出一个未捕获到的 Exception 或 Error。
3.另一个线程调用一个弃用的 stop() 方法。弃用是指这些方法仍然存在,但是您不应该在新代码中使用它们,并且应该尽量从现有代码中除去它们。
当 Java 程序中的所有线程都完成时,程序就退出了
加入线程
Thread API 包含了等待另一个线程完成的方法:join() 方法。当调用 Thread.join() 时,调用线程将阻塞,直到目标线程完成为止。
Thread.join() 通常由使用线程的程序使用,以将大问题划分成许多小问题,每个小问题分配一个线程。本章结尾处的示例创建了十个线程,启动它们,然后使用 Thread.join() 等待它们全部完成。
调度
除了何时使用 Thread.join() 和 Object.wait() 外,线程调度和执行的计时是不确定的。如果两个线程同时运行,而且都不等待,您必须假设在任何两个指令之间,其它线程都可以运行并修改程序变量。
如果线程要访问其它线程可以看见的变量,如从静态字段(全局变量)直接或间接引用的数据,则必须使用同步以确保数据一致性。
在以下的简单示例中,我们将创建并启动两个线程,每个线程都打印两行到 System.out:
1 2 A B
1 A 2 B
1 A B 2
A 1 2 B
A 1 B 2
A B 1 2
不仅不同机器之间的结果可能不同,而且在同一机器上多次运行同一程序也可能生成不同结果。永远不要假设一个线程会在另一个线程之前执行某些操作,除非您已经使用了同步以强制一个特定的执行顺序。
休眠
Thread API 包含了一个 sleep() 方法,它将使当前线程进入等待状态,直到过了一段指定时间,或者直到另一个线程对当前线程的 Thread 对象调用了 Thread.interrupt(),从而中断了线程。当过了指定时间后,线程又将变成可运行的,并且回到调度程序的可运行线程队列中。
如果线程是由对 Thread.interrupt() 的调用而中断的,那么休眠的线程会抛出InterruptedException,这样线程就知道它是由中断唤醒的,就不必查看计时器是否过期。
Thread.yield() 方法就象 Thread.sleep()一样,但它并不引起休眠,而只是暂停当前线程片刻,这样其它线程就可以运行了。在大多数实现中,当较高优先级的线程调用 Thread.yield() 时,较低优先级的线程就不会运行。
守护程序线程
我们提到过当 Java 程序的所有线程都完成时,该程序就退出,但这并不完全正确。隐藏的系统线程,如垃圾收集线程和由 JVM 创建的其它线程会怎么样?我们没有办法停止这些线程。如果那些线程正在运行,那么 Java 程序怎么退出呢?这些系统线程称作守护程序线程。Java 程序实际上是在它的所有非守护程序线程完成后退出的。任何线程都可以变成守护程序线程。可以通过调用 Thread.setDaemon() 方法来指明某个线程是守护程序线程。您也许想要使用守护程序线程作为在程序中创建的后台线程,如计时器线程或其它延迟的事件线程,只有当其它非守护程序线程正在运行时,这些线程才有用。
示例:用多个线程分解大任务
在这个示例中,TenThreads 显示了一个创建了十个线程的程序,每个线程都执行一部分工作。该程序等待所有线程全部完成,然后收集结果。
小结
就象程序一样,线程有生命周期:它们启动、执行,然后完成。一个程序或进程也许包含多个线程,而这些线程看来互相单独地执行。
线程是通过实例化 Thread 对象或实例化继承 Thread 的对象来创建的,但在对新的 Thread 对象调用 start() 方法之前,这个线程并没有开始执行。当线程运行到其 run() 方法的末尾或抛出未经处理的异常时,它们就结束了。
sleep() 方法可以用于等待一段特定时间;而 join() 方法可能用于等到另一个线程完成。
----------
创建线程
在 Java 程序中创建线程有几种方法。每个 Java 程序至少包含一个线程:主线程。其它线程都是通过 Thread 构造器或实例化继承类 Thread 的类来创建的。当我们讨论 Java 程序中的线程时,也许会提到两个相关实体:完成工作的实际线程或代表线程的 Thread 对象。正在运行的线程通常是由操作系统创建的;Thread 对象是由 Java VM 创建的,作为控制相关线程的一种方式。
创建线程和启动线程并不相同
在一个线程对新线程的 Thread 对象调用 start() 方法之前,这个新线程并没有真正开始执行。Thread 对象在其线程真正启动之前就已经存在了,而且其线程退出之后仍然存在。这可以让您控制或获取关于已创建的线程的信息,即使线程还没有启动或已经完成了。
通常在构造器中通过 start() 启动线程并不是好主意。这样做,会把部分构造的对象暴露给新的线程。如果对象拥有一个线程,那么它应该提供一个启动该线程的 start() 或 init() 方法,而不是从构造器中启动它。
结束线程
线程会以以下三种方式之一结束:
1.线程到达其 run() 方法的末尾。
2.线程抛出一个未捕获到的 Exception 或 Error。
3.另一个线程调用一个弃用的 stop() 方法。弃用是指这些方法仍然存在,但是您不应该在新代码中使用它们,并且应该尽量从现有代码中除去它们。
当 Java 程序中的所有线程都完成时,程序就退出了
加入线程
Thread API 包含了等待另一个线程完成的方法:join() 方法。当调用 Thread.join() 时,调用线程将阻塞,直到目标线程完成为止。
Thread.join() 通常由使用线程的程序使用,以将大问题划分成许多小问题,每个小问题分配一个线程。本章结尾处的示例创建了十个线程,启动它们,然后使用 Thread.join() 等待它们全部完成。
调度
除了何时使用 Thread.join() 和 Object.wait() 外,线程调度和执行的计时是不确定的。如果两个线程同时运行,而且都不等待,您必须假设在任何两个指令之间,其它线程都可以运行并修改程序变量。
如果线程要访问其它线程可以看见的变量,如从静态字段(全局变量)直接或间接引用的数据,则必须使用同步以确保数据一致性。
在以下的简单示例中,我们将创建并启动两个线程,每个线程都打印两行到 System.out:
public class TwoThreads { public static class Thread1 extends Thread { public void run() { System.out.println("A"); System.out.println("B"); } } public static class Thread2 extends Thread { public void run() { System.out.println("1"); System.out.println("2"); } } public static void main(String[] args) { new Thread1().start(); new Thread2().start(); } }我们并不知道这些行按什么顺序执行,只知道“1”在“2”之前打印,以及“A”在“B”之前打印。输出可能是以下结果中的任何一种:
1 2 A B
1 A 2 B
1 A B 2
A 1 2 B
A 1 B 2
A B 1 2
不仅不同机器之间的结果可能不同,而且在同一机器上多次运行同一程序也可能生成不同结果。永远不要假设一个线程会在另一个线程之前执行某些操作,除非您已经使用了同步以强制一个特定的执行顺序。
休眠
Thread API 包含了一个 sleep() 方法,它将使当前线程进入等待状态,直到过了一段指定时间,或者直到另一个线程对当前线程的 Thread 对象调用了 Thread.interrupt(),从而中断了线程。当过了指定时间后,线程又将变成可运行的,并且回到调度程序的可运行线程队列中。
如果线程是由对 Thread.interrupt() 的调用而中断的,那么休眠的线程会抛出InterruptedException,这样线程就知道它是由中断唤醒的,就不必查看计时器是否过期。
Thread.yield() 方法就象 Thread.sleep()一样,但它并不引起休眠,而只是暂停当前线程片刻,这样其它线程就可以运行了。在大多数实现中,当较高优先级的线程调用 Thread.yield() 时,较低优先级的线程就不会运行。
守护程序线程
我们提到过当 Java 程序的所有线程都完成时,该程序就退出,但这并不完全正确。隐藏的系统线程,如垃圾收集线程和由 JVM 创建的其它线程会怎么样?我们没有办法停止这些线程。如果那些线程正在运行,那么 Java 程序怎么退出呢?这些系统线程称作守护程序线程。Java 程序实际上是在它的所有非守护程序线程完成后退出的。任何线程都可以变成守护程序线程。可以通过调用 Thread.setDaemon() 方法来指明某个线程是守护程序线程。您也许想要使用守护程序线程作为在程序中创建的后台线程,如计时器线程或其它延迟的事件线程,只有当其它非守护程序线程正在运行时,这些线程才有用。
示例:用多个线程分解大任务
在这个示例中,TenThreads 显示了一个创建了十个线程的程序,每个线程都执行一部分工作。该程序等待所有线程全部完成,然后收集结果。
/** * Creates ten threads to search for the maximum value of a large matrix. * Each thread searches one portion of the matrix. */ public class TenThreads { private static class WorkerThread extends Thread { int max = Integer.MIN_VALUE; int[] ourArray; public WorkerThread(int[] ourArray) { this.ourArray = ourArray; } // Find the maximum value in our particular piece of the array public void run() { for (int i = 0; i < ourArray.length; i++) max = Math.max(max, ourArray[i]); } public int getMax() { return max; } } public static void main(String[] args) { WorkerThread[] threads = new WorkerThread[10]; int[][] bigMatrix = getBigHairyMatrix(); int max = Integer.MIN_VALUE; // Give each thread a slice of the matrix to work with for (int i=0; i < 10; i++) { threads[i] = new WorkerThread(bigMatrix[i]); threads[i].start(); } // Wait for each thread to finish try { for (int i=0; i < 10; i++) { threads[i].join(); max = Math.max(max, threads[i].getMax()); } } catch (InterruptedException e) { // fall through } System.out.println("Maximum value was " + max); } }
小结
就象程序一样,线程有生命周期:它们启动、执行,然后完成。一个程序或进程也许包含多个线程,而这些线程看来互相单独地执行。
线程是通过实例化 Thread 对象或实例化继承 Thread 的对象来创建的,但在对新的 Thread 对象调用 start() 方法之前,这个线程并没有开始执行。当线程运行到其 run() 方法的末尾或抛出未经处理的异常时,它们就结束了。
sleep() 方法可以用于等待一段特定时间;而 join() 方法可能用于等到另一个线程完成。
相关文章推荐
- java多线程与并发之java线程简介(六)
- java多线程与并发之java线程简介(四)
- java多线程与并发之java线程简介(三)
- java多线程与并发之java线程简介(一)
- java多线程与并发之java线程简介(五)
- java并发多线程,线程的创建启动
- java多线程与并发之创建线程的几种方式
- java多线程与高并发库应用(一)线程基础概念
- Java多线程与并发应用-(4)-传统线程通信技术试题
- 09_张孝祥_多线程_java5线程并发库的应用_线程池
- 【Java多线程与并发库】20.java线程面试题3
- java多线程简介及线程创建方式
- 初学Java多线程:线程简介
- 初学Java多线程:线程简介
- 多线程并发库高级应用 之 java5中的线程并发库--线程池、Callable&Future
- java多线程之线程并发库原子性操作类
- Java多线程与并发应用-(6)-多个线程之间共享对象和数据的方式
- Java多线程与并发学习之(四):线程常用方法
- Java 多线程编程之一 进程与线程,并发和并行的区别
- java多线程系列_线程简介(1)