一、简介

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

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

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

  本章呈现了一系列的代码秘诀,这些代码秘诀演示了如何使用 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 溢出。

  重要:本系列翻译文档也会在本人的微信公众号(此山是我开)第一时间发布,欢迎大家关注。

  

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

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

    十一.处理线程组中的未控制异常 每种编程语言一个很重要的特性就是其所提供的用来处理程序中错误情况的机制.Java语言和其他的现代语言一样,是提供了异常机制来处理对象程序中的错误.Java提供了很多的类 ...

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

    九.使用线程本地变量 一个并发程序的最关键特征就是共享数据.这个特性在那些继承了 Thread 类或者 实现了 Runnable 接口的对象上显得更加重要. 如果你创建一个实现了 Runnable 接 ...

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

    七.创建和运行一个后台线程 Java中有一种特别的线程叫做 deamon(后台) 线程.这类线程具有非常低的权限,并且只有在同一个程序中没有其他的正常线程在运行时才会运行.注意:当一个程序中只剩下后台 ...

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

    三.中断一个线程 一个拥有多个线程的Java程序要结束,需要满足两个条件之一:一是所有的非后台线程都执行结束了:二是某个线程执行了 System.exit() 方法.当你想要终结一个运行中的Java程 ...

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

    五.睡眠和唤醒一个线程 有时,你会想要在一段特定的时间后再去中断线程的运行.举个例子,程序中的一个线程每一分钟检查一次传感器的状态,剩余的时间,线程应该处于空闲的状态.在这段空闲时间里,线程不会使用计 ...

  6. Java 7 Concurrency Cookbook 翻译 序言

    在日常的Java代码开发过程中,很难免地有对多线程的需求,掌握java多线程和并发的机制也是Java程序员写出更健壮和高效代码的基础.笔者找寻国内已出版的关于Java多线程和并发的的中文书籍和翻译书籍 ...

  7. java的优点和误解 《java核心技术卷i》第一章

    <java核心技术卷i>第一章主要内容包括三点: 1:Java白皮书的关键术语:描述Java的十一个关键字: 2:Java applet 3 :关于Java的常见误解   1:第一章:Ja ...

  8. java JDK8 学习笔记——第11章 线程和并行API

    第11章 线程与并行API 11.1 线程 11.1.1 线程 在java中,如果想在main()以外独立设计流程,可以撰写类操作java.lang.Runnable接口,流程的进入点是操作在run( ...

  9. Java 螺纹第三版 第一章Thread介绍、 第二章Thread创建和管理学习笔记

    第一章 Thread导论 为何要用Thread ? 非堵塞I/O      I/O多路技术      轮询(polling)      信号 警告(Alarm)和定时器(Timer) 独立的任务(Ta ...

随机推荐

  1. 怎样用命令行编译C#程序

    1. 把程序拷贝至记事本 2.另存为*cs格式 3.找到VS2015提供的命令提示 4.要把命令行指向程序所在的目录(可以有个小软件) 如果在其他的盘符,先敲D:,然后再cd 5.输入csc hell ...

  2. C++中int,float,string,char*的转换(待续)

    //float转string char a[100]; float b = 1.234; sprintf(a, "%f", b); string result(a); //int转 ...

  3. Javascript setTimeout 带参数延迟执行 闭包实现

    不是原创,只是 借鉴别人的成果,我在此纪念 1.htm function GetDateT() { var d,s; d = new Date(); s = d.getFullYear() + &qu ...

  4. JVM内存简单理解

    1.首先简单说一下CPU与内存之间的关系 CPU运转速度快,磁盘的读写速度远远不及CPU运转速度,所以设计了内存来缓冲CPU等待磁盘读写:随着CPU的发展,内存读写也远远跟不上CPU的读写速度,CPU ...

  5. Stack类

    栈是采用先进后出的数据存储方式,每一个栈都包含一个栈顶,每次出栈是将栈顶的数据取出. import java.util.Stack; //=============================== ...

  6. 使用ASP.NET Web Api构建基于REST风格的服务实战系列教程【五】——在Web Api中实现Http方法(Put,Post,Delete)

    系列导航地址http://www.cnblogs.com/fzrain/p/3490137.html 前言 在Web Api中,我们对资源的CRUD操作都是通过相应的Http方法来实现——Post(新 ...

  7. 为什么可以用while(cin)?

    为什么可以用while(cin)?   /** * @brief The quick-and-easy status check. * * This allows you to write const ...

  8. Unity 下载

    Unity历史版本 http://wiki.ceeger.com/unity:history#unity_522f1 UNITY 下载存档 http://unity3d.com/cn/get-unit ...

  9. Ios 消息推送

    手把手教你做iOS推送 http://www.cocoachina.com/industry/20130321/5862.html http://www.cnblogs.com/cdts_change ...

  10. Apache配置--用户认证(针对目录访问)-update2015-05-02

    通过Apache配置可以限制用户对目录的访问,会弹出像phpadmin一样的登陆框. ========================================================= ...