Java多线程之线程的启动

一、前言

  启动线程的方法有如下两种。

  • 利用Thread 类的子类的实例启动线程
  • 利用Runnable 接口的实现类的实例启动线程

  最后再介绍下java.util.concurrent.ThreadFactory中的线程创建

  下面分别做以介绍

二、利用Thread 类的子类启动线程

  这里来学习一下利用Thread 类的子类的实例来启动线程的方法,即上一篇博文中使用的方法。我们构造一个PrintThread 类表示输出1000次指定字符串的线程。输出的字符串通过构造函数的参数传入,并赋给message 字段。PrintThread 类被声明为Thread 的子类。

  如下表示输出10 000 次指定字符串的线程的类PrintThread(PrintThread.java)

  public class PrintThread extends Thread {

    private String message;

    public PrintThread(String message) {

      this.message = message;

    }

    @Override

    public void run() {

      for (int i = 0; i < 1000; i++) {

        System.out.println(message);

      }

    }
  }

  Main 类是用于创建上面声明的PrintThread 类的两个实例并利用它们来启动两个线程的程序。

  利用PrintThread 类启动2 个线程(Main.java)

  public class Main {

    public static void main(String[] args) {

      new PrintThread("Good!").start();

      new PrintThread("Nice!").start();

    }
  }

  main 方法创建了PrintThread 类的实例,并直接(不赋给某个变量)调用了该实例的start 方法。

  start 方法会启动新的线程,然后由启动的新线程调用PrintThread 类的实例的run 方法。

  最终结果就是由新启动的线程执行1000次Good! 字符串输出。

  为了程序简洁,上面的程序只用一条语句启动了线程。但实际上,“创建PrintThread 的实例”和“启动该实例对应的线程”是两个完全不同的处理。也就是说,即便已经创建了实例,但是如果不调用start 方法,线程也不会被启动。上面这条语句也可以像下面这样写成两句。

  另外,这里再提醒大家注意,“PrintThread 的实例”和“线程本身”不是同一个东西。即便创建了PrintThread 的实例,线程也并没有启动,而且就算线程终止了,PrintThread 的实例也不会消失。

  主线程在Main 类的main 方法中启动了两个线程。随后main 方法便会终止,主线程也会跟着终止。但整个程序并不会随之终止,因为启动的两个线程在字符串输出之前是不会终止的。直到所有的线程都终止后,程序才会终止。也就是说,当这两个线程都终止后,程序才会终止。

  关于程序的终止:

  Java 程序的终止是指除守护线程(Daemon Thread)以外的线程全部终止。守护线程是执行后台作业的线程。我们可以通过setDaemon 方法把线程设置为守护线程。

  创建Thread 类的子类、创建子类的实例、调用start 方法——这就是利用Thread 类的子类启动线程的方法。

三、利用Runnable 接口启动线程

  这里来学习一下利用Runnable 接口的实现类的实例来启动线程的方法。Runnable 接口包含在java.lang 包中,声明如下。

  public interface Runnable {

    public abstract void run();

  }

  Runnable 接口的实现类必须要实现run 方法,否则要声明为抽象方法。

  现在我们来构造Printer类表示一个输出10 000 次指定字符串的线程。输出的字符串通过构造函数的参数传入,并赋给message 字段。由于Printer 类实现(implements)了Runnable 接口,所以此时也就无需再将Printer 类声明为Thread 类的子类。

  输出指定字符串的Printer 类(Printer.java)

  public class Printer implements Runnable {

    private String message;
    public Printer(String message) {
      this.message = message;
    }
    @Override
    public void run() {
      for (int i = 0; i < 1000; i++) {
        System.out.println(message);
      }
    }
  }

  Main 类是用于创建两个Printer 类的实例,并利用它们来启动两个线程的程序。

  利用Runnable 接口启动两个线程(Main.java)

  public class Main {

    public static void main(String[] args) {

      new Thread(new Printer("Good")).start();

      new Thread(new Printer("Nice")).start();

    }
  }

  创建Thread 的实例时,构造函数的参数中会传入Printer 类的实例,然后会调用start 方法,启动线程。

  start 方法会启动新的线程,然后由启动的新线程调用Printer 类的实例的run 方法。最终结果就是由新启动的线程执行1000次Good! 字符串输出。上面这条语句也可以像下面这样写成三句。

  创建Runnable 接口的实现类,将实现类的实例作为参数传给Thread 的构造函数,调用start 方法——这就是利用Runnable 接口启动线程的方法。

  不管是利用Thread 类的子类的方法(1),还是利用Runnable 接口的实现类的方法(2),启动新线程的方法最终都是Thread 类的start 方法。

  关于Thread 类和Runnable 方法

  Thread 类本身还实现了Runnable 接口,并且持有run 方法,但Thread 类的run 方法主体是空的,不执行任何操作。Thread 类的run 方法通常都由子类的run 方法重写(override)。

四、java.util.concurrent.ThreadFactory 中的线程创建

  java.util.concurrent 包中包含一个将线程创建抽象化的ThreadFactory 接口。利用该接口,我们可以将以Runnable 作为传入参数并通过new 创建Thread 实例的处理隐藏在ThreadFactory 内部。典型用法如下所示。默认的ThreadFactory 对象是通过Executors.defaultThreadFactory 方法获取的。

  此处运行的Printer类与上面的Printer 类相同

  利用ThreadFactory 新启动线程(Main.java)

  import java.util.concurrent.Executors;
  import java.util.concurrent.ThreadFactory;

  public class Main2 {

    public static void main(String[] args) {

      ThreadFactory factory = Executors.defaultThreadFactory();

      factory.newThread(new Printer("Good!")).start();

      for (int i = 0; i < 1000; i++) {

        System.out.println("Nice!");

      }

    }

  }

  参考:图解Java多线程设计模式

Java多线程之线程的启动的更多相关文章

  1. Java多线程之线程其他类

    Java多线程之线程其他类 实际编码中除了前面讲到的常用的类之外,还有几个其他类也有可能用得到,这里来统一整理一下: 1,Callable接口和Future接口 JDK1.5以后提供了上面这2个接口, ...

  2. Java多线程之线程的同步

    Java多线程之线程的同步 实际开发中我们也经常提到说线程安全问题,那么什么是线程安全问题呢? 线程不安全就是说在多线程编程中出现了错误情况,由于系统的线程调度具有一定的随机性,当使用多个线程来访问同 ...

  3. Java多线程之线程的控制

    Java多线程之线程的控制 线程中的7 种非常重要的状态:  初始New.可运行Runnable.运行Running.阻塞Blocked.锁池lock_pool.等待队列wait_pool.结束Dea ...

  4. Java多线程02(线程安全、线程同步、等待唤醒机制)

    Java多线程2(线程安全.线程同步.等待唤醒机制.单例设计模式) 1.线程安全 如果有多个线程在同时运行,而这些线程可能会同时运行这段代码.程序每次运行结果和单线程运行的结果是一样的,而且其他的变量 ...

  5. java多线程与线程间通信

    转自(http://blog.csdn.net/jerrying0203/article/details/45563947) 本文学习并总结java多线程与线程间通信的原理和方法,内容涉及java线程 ...

  6. Java多线程之线程的生命周期

    Java多线程之线程的生命周期 一.前言 当线程被创建并启动以后,它既不是一启动就进入了执行状态,也不是一直处于执行状态.在线程的生命周期中,它要经过新建(New).就绪(Runnable).运行(R ...

  7. Java多线程| 01 | 线程概述

    Java多线程| 01 | 线程概述 线程相关概念 进程与线程 进程:进程(Process)是计算机中的程序关于某数据集合上的一次运行活动,是操作系统进行资源分配与调度的基本单位.可以把进程简单的理解 ...

  8. Java多线程之线程的通信

    Java多线程之线程的通信 在总结多线程通信前先介绍一个概念:锁池.线程因为未拿到锁标记而发生的阻塞不同于前面五个基本状态中的阻塞,称为锁池.每个对象都有自己的锁池的空间,用于放置等待运行的线程.这些 ...

  9. Java多线程父子线程关系 多线程中篇(六)

    有的时候对于Java多线程,我们会听到“父线程.子线程”的概念. 严格的说,Java中不存在实质上的父子关系 没有方法可以获取一个线程的父线程,也没有方法可以获取一个线程所有的子线程 子线程的消亡与父 ...

随机推荐

  1. 在Ubuntu中安装Docker和docker的使用

    1.在Ubuntu中安装Docker 更新ubuntu的apt源索引 sudo apt-get update 安装包允许apt通过HTTPS使用仓库 sudo apt-get install \ ap ...

  2. Java:jdbc连接mysql数据库

    安装eclipse和mysql的步骤这里不赘述了. 1.一定要下jar包 要想实现连接数据库,要先下载mysql-connector-java-5.1.47(或者其他版本)的jar包.低版本的jar包 ...

  3. Java_异常介绍

    今日内容介绍: 掌握异常概述 理解异常的基础操作以及最简单的捕获处理 理解多异常捕获处理 理解声明抛出异常 掌握自定义异常 掌握异常处理注意事项 异常 什么是异常?Java代码在运行时期发生的问题就是 ...

  4. C#托盘程序设置

    打开Microsoft Visual Studio 2010,新建解决方案--添加项目--托盘的实现     从工具栏里,把NotifyIcon控件拖到窗体上,并设置属性: 1.visible 设置默 ...

  5. docker的基本安装和命令详解

    docker的安装 yum install docker-io docker的启动 /bin/systemctl start docker.service docker查找镜像 docker sear ...

  6. 全文检索方案Elasticsearch【Python-Django 服务端开发】

    更详细请看 https://www.elastic.co/cn/ 1. 全文检索和搜索引擎原理 商品搜索需求 当用户在搜索框输入商品关键字后,我们要为用户提供相关的商品搜索结果. 商品搜索实现 可以选 ...

  7. html以前没有学到的标签

    <q>标签,短文本引用 <blockquote>标签,长文本引用 <address>标签,为网页加入地址信息 <code>标签,插入单行代码 <p ...

  8. FB的新专利竟要监看使用者的脸

    大家应该会很好奇Facebook又在搞什么新花招,这个专利的名称是"Techniques for emotion detection and content delivery",其 ...

  9. 自定义SWT控件七之自定义Shell(可伸缩窗口)

    7.可伸缩窗口 该自定义窗口可以通过鼠标随意更改窗口大小 package com.hikvision.encapsulate.view.control.shell; import org.eclips ...

  10. [ubuntu][deepin]系统增加自定义开机启动项

    [ubuntu][deepin]系统增加自定义开机启动项 进行配置 cd /etc/init.d/ ls vim myScript nginx实例 #! /bin/sh # chkconfig: # ...