美文网首页
Java 线程

Java 线程

作者: OldChicken_ | 来源:发表于2018-11-27 19:07 被阅读2次

    本文主要摘取自Java 线程简介


    线程基础

    什么是线程?

    几乎每种操作系统都支持进程的概念 ―― 进程就是在某种程度上相互隔离的、独立运行的程序。
    线程化是允许多个活动共存于一个进程中的工具。大多数现代的操作系统都支持线程,而且线程的概念以各种形式已存在了好多年。Java 是第一个在语言本身中显式地包含线程的主流编程语言,它没有把线程化看作是底层操作系统的工具。

    每个 Java 程序都使用线程

    每个 Java 程序都至少有一个线程 ― 主线程。当一个 Java 程序启动时,JVM 会创建主线程,并在该线程中调用程序的 main() 方法。

    JVM 还创建了其它线程,您通常都看不到它们 ― 例如,与垃圾收集、对象终止和其它 JVM 内务处理任务相关的线程。其它工具也创建线程,如 AWT(抽象窗口工具箱(Abstract Windowing Toolkit))或 Swing UI 工具箱、servlet 容器、应用程序服务器和 RMI(远程方法调用(Remote Method Invocation))。

    为什么使用线程?

    在 Java 程序中使用线程有许多原因。如果您使用 Swing、servlet、RMI 或 Enterprise JavaBeans(EJB)技术,您也许没有意识到您已经在使用线程了。
    使用线程的一些原因是它们可以帮助:

    • 使 UI 响应更快
    • 利用多处理器系统
    • 简化建模
    • 执行异步或后台处理

    线程的生命周期

    创建线程

    在 Java 程序中创建线程有几种方法。每个 Java 程序至少包含一个线程:主线程。其它线程都是通过 Thread 构造器或实例化继承类 Thread 的类来创建的。

    Java 线程可以通过直接实例化 Thread 对象或实例化继承 Thread 的对象来创建其它线程。在线程基础 中的示例(其中,我们在十秒钟之内计算尽量多的素数)中,我们通过实例化 CalculatePrimes 类型的对象(它继承了 Thread),创建了一个线程。

    当我们讨论 Java 程序中的线程时,也许会提到两个相关实体:完成工作的实际线程或代表线程的 Thread 对象。正在运行的线程通常是由操作系统创建的;Thread 对象是由 Java VM 创建的,作为控制相关线程的一种方式。

    结束线程

    线程会以以下三种方式之一结束:

    • 线程到达其 run() 方法的末尾。
    • 线程抛出一个未捕获到的 ExceptionError
    • 另一个线程调用一个弃用的 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() 时,较低优先级的线程就不会运行。

    CalculatePrimes 示例使用了一个后台线程计算素数,然后休眠十秒钟。当计时器过期后,它就会设置一个标志,表示已经过了十秒。

    守护程序线程

    我们提到过当 Java 程序的所有线程都完成时,该程序就退出,但这并不完全正确。隐藏的系统线程,如垃圾收集线程和由 JVM 创建的其它线程会怎么样?我们没有办法停止这些线程。如果那些线程正在运行,那么 Java 程序怎么退出呢?

    这些系统线程称作守护程序线程。Java 程序实际上是在它的所有非守护程序线程完成后退出的。

    任何线程都可以变成守护程序线程。可以通过调用 Thread.setDaemon() 方法来指明某个线程是守护程序线程。您也许想要使用守护程序线程作为在程序中创建的后台线程,如计时器线程或其它延迟的事件线程,只有当其它非守护程序线程正在运行时,这些线程才有用。

    小结

    就象程序一样,线程有生命周期:它们启动、执行,然后完成。一个程序或进程也许包含多个线程,而这些线程看来互相单独地执行。

    线程是通过实例化 Thread 对象或实例化继承 Thread 的对象来创建的,但在对新的 Thread 对象调用 start() 方法之前,这个线程并没有开始执行。当线程运行到其 run() 方法的末尾或抛出未经处理的异常时,它们就结束了。

    sleep() 方法可以用于等待一段特定时间;而 join() 方法可能用于等到另一个线程完成。

    相关文章

      网友评论

          本文标题:Java 线程

          本文链接:https://www.haomeiwen.com/subject/kpwjqqtx.html