Java 7 Concurrency Cookbook 翻译 第一章 线程管理之一

一、简介

  在计算机的世界里,当我们谈论并发时,我们指的是一系列的任务同时运行于一个计算机中。这里说的同时运行,在计算机拥有多于一个处理器或者是一个多核处理器的时候才是真正的同时,在计算机只拥有单核处理器的时候,它指的是表面上的同时运行。

  所有的现代操作系统都允许并发任务的执行。在听歌和阅读网页上新闻的同时,你还能阅读电子邮件。我们可以说这种类型的并发是进程级别的并发。但在一个进程内部,我们也可以拥有多个同时运行的任务。那些运行在一个进程中的并发任务被称作线程。

  与并发相关的另一个概念是并行。它与并发之间存在着紧密的联系和区别。有人认为,在单核处理器中执行具有多个线程的进程就叫做并发,这个并发被认为是表面的并发。同时,在多核处理器或者多处理中执行具有多个线程的进程就叫做并行。其他人则认为,当一个进程的多个线程执行之间没有预定义好的顺序时就叫做并发,当使用多个线程去简化一个问题的求解,同时所有的线程按照一定的顺序执行时就叫做并行。

  本章呈现了一系列的代码秘诀,这些代码秘诀演示了如何使用 Java 7 API 去执行基本的线程操作。你可以从中学到在Java程序中如何创建和运行线程,如何控制线程的执行,如何分组线程并使用线程组的方式来操纵组内线程。

二、创建和运行一个线程

  在这个秘诀中,我们将学到如何在Java程序中去创建和运行一个线程。就像Java语言中的其他元素一样,线程也是以对象的形式存在。在Java中,创建线程有两种方式:

  (A) 继承 Thread 类,覆写 run() 方法

  (B) 创建一个新类,该类实现 Runnable 接口,该类的对象传给 Thread 类的对象

  在本秘诀中,我们通过一个创建和运行10个线程的简单程序来演示第二种方式.每个线程都是计算和打印输出1到10之间的乘法表。

public class Calculator implements Runnable{
    private int number;
    public Calculator(int number) {
        this.number = number;
    }
    @Override
    public void run() {
        for (int i = 1; i <= 10; i++) {
            System.out.printf("%s: %d * %d = %d\n",
                    Thread.currentThread().getName(),
                    number, i, i*number);
        }
    }
}

public class Main {
    public static void main(String[] args) {
        for (int i = 1; i <= 10; i++) {
            Calculator calculator = new Calculator(i);
            Thread thread = new Thread(calculator);
            thread.start();
        }
    }
}

  main()方法所在的执行线程是由JVM启动执行时创建的,一般我们称之为主线程。

  通过调用一个 Thread 对象的 start() 方法,我们创建了一个另外的执行线程。

  只有当程序的所有非后台线程结束后,该程序才算结束。但是要注意:一旦某一个线程执行了System.exit()指令,所有的线程都将终止执行,该程序也就结束了。

  创建一个 Thread 类的对象并没有创建一个新的执行线程。调用实现了 Runnable 接口的对象的 run() 方法也不会创建一个新线程。只有调用 Thread 对象的 start() 方法才创建新线程。

三、获取和设置线程信息

  Thread 类保存有一些能帮助我们识别一个线程的信息属性。通过这些属性,我们可以知道它的状态,控制它的优先级。这些属性是:

  (A) ID:每个线程的唯一标识符

  (B) Name:线程的名字

  (C) Priority:线程的优先级,1到10之间,1最低,不建议修改和利用此属性

  (D) Status:线程的状态,六种可能:新建、可运行、被阻塞、等待、等待时间、被终结

  在本秘诀中,我们创建拥有10个线程的程序,设置10个线程的名字和优先级,然后展示它们的状态知道它们结束,这些线程会计算一个数字的乘法表。

public class Calculator implements Runnable{
    private int number;
    public Calculator(int number) {
        this.number = number;
    }
    @Override
    public void run() {
        for (int i = 1; i <= 10; i++) {
            System.out.printf("%s: %d * %d = %d\n",
                    Thread.currentThread().getName(),
                    number, i, i*number);
        }
    }
}

public class Main {
    public static void main(String[] args) {
        Thread threads[] = new Thread[10];
        Thread.State status[] = new Thread.State[10];

        for (int i = 0; i < 10; i++) {
            threads[i] = new Thread(new Calculator(i));
            if ((i%2) == 0) {
                threads[i].setPriority(Thread.MAX_PRIORITY);
            } else {
                threads[i].setPriority(Thread.MIN_PRIORITY);
            }
            threads[i].setName("Thread " +i);
        }

        try (FileWriter fw = new FileWriter("log.txt");
                PrintWriter pw = new PrintWriter(fw); ) {
            for (int i = 0; i < 10; i++) {
                pw.println("Main : Status of Thread " + i + " : " +
            threads[i].getState());
                status[i] = threads[i].getState();
            }

            for (int i = 0; i < 10; i++) {
                threads[i].start();
            }

            boolean finish = false;
            while (!finish) {
                for (int i = 0; i < 10; i++) {
                    if (threads[i].getState() != status[i]) {
                        writeThreadInfo(pw, threads[i], status[i]);
                        status[i] = threads[i].getState();
                    }
                }
                finish = true;
                for (int i = 0; i < 10; i++) {
                    finish = finish && (threads[i].getState() == State.TERMINATED);
                }
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    private static void writeThreadInfo(PrintWriter pw,
            Thread thread, State state) {
        pw.printf("Main : Id %d - %s\n", thread.getId(), thread.getName());
        pw.printf("Main : Priority: %d\n", thread.getPriority());
        pw.printf("Main : Old State: %s\n", state);
        pw.printf("Main : New State: %s\n", thread.getState());
        pw.printf("Main : *******************************\n");
    }
}

  如果不指定线程名字,JVM会自动给它分配 Thread-XX 格式的线程名。线程的ID和Status是不能修改的。

  如果是想在实现了 Runnable 接口的类的对象中访问线程的信息,可以使用 Thread 类的静态方法 currentThread() 获取执行当前代码的 Thread 对象,并以此来访问线程信息。

  需要注意的是:setPriority() 方法可能抛出 IllegalArgumentException 溢出。

  

  

时间: 2024-12-22 02:28:41

Java 7 Concurrency Cookbook 翻译 第一章 线程管理之一的相关文章

Java 7 Concurrency Cookbook 翻译 第一章 线程管理之四

七.创建和运行一个后台线程 Java中有一种特别的线程叫做 deamon(后台) 线程.这类线程具有非常低的权限,并且只有在同一个程序中没有其他的正常线程在运行时才会运行.注意:当一个程序中只剩下后台线程时,JVM会终结所有的后台线程并结束程序. 由于这个特性,后台线程一般用于为同一个程序中的其他正常线程提供服务.这种后台线程一般都有一个无限的循环在等待请求服务或者执行请求的任务.由于不知道它们何时可以获得CPU的调用执行,同时在没有其他正常线程的情况下会被JVM终结,所以后台线程不能用于执行重

Java 7 Concurrency Cookbook 翻译 第一章 线程管理之二

三.中断一个线程 一个拥有多个线程的Java程序要结束,需要满足两个条件之一:一是所有的非后台线程都执行结束了:二是某个线程执行了 System.exit() 方法.当你想要终结一个运行中的Java程序或者程序的用户想要取消一个线程正在执行的任务时,你都需要结束一个线程. Java提供中断机制来表明我们想要终止一个线程.这个机制的核心是线程必须要检查自己是否被中断,而且线程自己决定是否响应中断请求.线程可以忽略该中断请求而继续执行. 在本秘诀中,我们将开发一个程序,这个程序创建线程,5秒后使用中

Java 7 Concurrency Cookbook 翻译 第一章 线程管理之六

十一.处理线程组中的未控制异常 每种编程语言一个很重要的特性就是其所提供的用来处理程序中错误情况的机制.Java语言和其他的现代语言一样,是提供了异常机制来处理对象程序中的错误.Java提供了很多的类来对应不同的错误.当Java检查到这些错误时,会抛出对应的异常对象.你可以直接使用那些异常类或者实现自己的异常类来处理程序中出项的错误情况. Java同时提供了捕获和处理异常对象的机制.异常必须被捕获或者重新抛出来.这类异常称为检测异常.还有一类异常不必捕获和处理,称为不检测异常. 在本秘诀中,我们

Java 7 Concurrency Cookbook 翻译 第一章 线程管理之三

五.睡眠和唤醒一个线程 有时,你会想要在一段特定的时间后再去中断线程的运行.举个例子,程序中的一个线程每一分钟检查一次传感器的状态,剩余的时间,线程应该处于空闲的状态.在这段空闲时间里,线程不会使用计算机的任何资源.一分钟后,线程已经准备好了,才让JVM选择调用它继续执行.你可以使用 Thread 类的 sleep() 方法来达到此目的.该方法接受一个 int 类型参数表明线程挂起不运行的毫秒数.当睡眠时间结束,线程转移到可运行状态等待JVM的调度. TimeUnit 枚举类的某个成员同样具有

第一章线程管理

Java 7 并发编程实战手册目录 代码下载(https://github.com/Wang-Jun-Chao/java-concurrency) 第一章线程管理 1.1简介 在计算机领域中,我们说的并发(Concurrency)是指一系列任务的同时运行.如果一 台电脑有多个处理器或者有一个多核处理器,这个同时性(Simultaneity)是真正意义的并 发:但是一台电脑只有一个单核处理器,这个同时性并不是真正的并发 与并发相关的另一个概念是并行(Parallelism).与并发有不同的定义一样

Java 7 Concurrency Cookbook 翻译 序言

在日常的Java代码开发过程中,很难免地有对多线程的需求,掌握java多线程和并发的机制也是Java程序员写出更健壮和高效代码的基础.笔者找寻国内已出版的关于Java多线程和并发的的中文书籍和翻译书籍,大家一致推荐的是<Java Concurrency in Practice>,笔者暂时还没有看英文原版,笔者看的是它的翻译版<Java并发编程实战>,笔者读起来感觉并不通畅,不知道是翻译的问题还是原版本来就写得不够流畅,同时感觉知识的深度也超过了入门的需求. 笔者在机缘巧合之下,发现

《深入理解Java虚拟机》读书笔记---第一章 走进Java

一.为什么要读此书 <深入理解Java虚拟机>这本书读了很多次,每次读都会有不一样的感受.首先说一下为什么要读这本书,如果把Java比喻成乾坤大挪移,那了解虚拟机的工作原理就是练习九阳神功,java语言是招式,对虚拟机的认识是内功心法,只有内功心法强大,所使的招式才强大,这就是为什么阳顶天只能把乾坤大挪移练到第四层,而张无忌能练到第七层.由于java虚拟机的强大,把很多功能都隐藏了,例如内容管理,垃圾回收机制等,使得很多java程序猿对这一块的知识所有缺失,编码的时候也是似懂非懂的,以至于遇到

《Java并发编程实战》第二章 线程安全性 读书笔记

一.什么是线程安全性 编写线程安全的代码 核心在于要对状态访问操作进行管理. 共享,可变的状态的访问 - 前者表示多个线程访问, 后者声明周期内发生改变. 线程安全性 核心概念是正确性.某个类的行为与其规范完全一致. 多个线程同时操作共享的变量,造成线程安全性问题. * 编写线程安全性代码的三种方法: 不在线程之间共享该状态变量 将状态变量修改为不可变的变量 在访问状态变量时使用同步 Java同步机制工具: synchronized volatile类型变量 显示锁(Explicit Lock

20172304 2018-2019《java软件结构与数据结构》 第一章 第二章学习总结

20172304 2018-2019<java软件结构与数据结构> 第一章 第二章学习总结 教材学习内容总结 第一章 概述 1.1软件质量: 高质量软件的几个特征: 正确性:软件在多大程度上满足其特定需求 可靠性:软件故障发生频率和危险程度 健壮性:出错情况下可以得到恰当处理的程度 可用性:用户学习和执行任务的难易程度 可维护性:对软件进行修改的难易程度 可重用性:软件组件可重用于其他软件系统开发的难易程度 可移植性:软件组件可以在多个计算机环境下使用的难易程度 运行效率:在不浪费资源的情况下