一、简介

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

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

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

  本章呈现了一系列的代码秘诀,这些代码秘诀演示了如何使用 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. SQL Server 2012 启动

    1.  启动 SQL Server Management studio 2. 选择登录模式 Server name:   "." 代表本地的数据库 Authertication: ...

  2. IIS------配置.Net 4.0

    转载: http://blog.csdn.net/mazhaojuan/article/details/7660657

  3. 整数分解 && 质因数分解

    输入整数(0-30)分解成所有整数之和.每四行换行一次. 一种方法是通过深度优先枚举出解.通过递归的方式来实现. #include <stdio.h> #include <strin ...

  4. Maven入门学习,安装及创建项目

    一.maven介绍: 1.maven是一个基于项目对象模型(POM Project Object Model),通过配置文件管理项目的工具(项目管理工具). 2.maven主要功能:发布项目(从编译到 ...

  5. Android学习笔记——ProgressBarHandler

    该工程的功能是实现点击按钮进度条按10%递增,使用的方式是Handler 以下的代码是MainActivity.java中的代码 package com.example.progressbarhand ...

  6. 关闭和启动adb服务命令

    在运行中输入 关闭——adb kill-server 重启——adb start-server

  7. Linux下Redis服务器安装配置

    说明:操作系统:CentOS1.安装编译工具yum install wget  make gcc gcc-c++ zlib-devel openssl openssl-devel pcre-devel ...

  8. yourphp的sql语句

    1.插入单条数据 $data[0]['cardid'] = $_POST['cardid']; $data[0]['name'] = $_POST['name']; $data[0]['mobile' ...

  9. Java并发编程核心方法与框架-Fork-Join分治编程(一)

    在JDK1.7版本中提供了Fork-Join并行执行任务框架,它的主要作用是把大任务分割成若干个小任务,再对每个小任务得到的结果进行汇总,这种开发方法也叫做分治编程,可以极大地利用CPU资源,提高任务 ...

  10. 基本linux命令

    1.mkdir mkdir 创建目录   mkdir -p 循环创建目录 2.cd     切换目录 3.pwd   查看当前路径 4.mkdir 删除一个空的目录 5.cp 复制文件/目录  -r用 ...