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. PHPStrom激活方法【亲测有效2018.4.23】

    直接用浏览器打开 http://idea.lanyus.com/ 点击页面中的"获得注册码", 然后在注册时切换至Activation Code选项,输入获得的注册码一长串字符串 ...

  2. 数据结构与算法基础之malloc()动态分配内存概述

    动态内存分配和释放: 动态构造一维数组: 假设动态构造一个Int型数组: int *p = (int *)malloc(int len); //还可以写作: int *p = (int *)mallo ...

  3. http.client.ResponseNotReady: Request-sent

    最近学习python写接口测试,使用的是connection.request 发现在测试一个发送报告接口时候,同一个接口,同样的脚本,只是一个参数传不同值,总提示:http.client.Respon ...

  4. SparkStreaming对接rabbitMQ

    /** * SparkStreaming对接rabbitmq java代码 */public class SparkConsumerRabbit { public static void main(S ...

  5. 【MySQL】Illegal mix of collations (utf8mb4_general_ci,IMPLICIT) and ...

    线上遇到这个问题,详细信息如下: SQL state [HY000]; error code [1267]; Illegal mix of collations (utf8mb4_general_ci ...

  6. JDK的可视化工具系列 (四) JConsole、VisualVM

    JConsole: Java监视与管理控制台 代码清单1: import java.util.*; public class JConsoleDemo { static class OOMObject ...

  7. 【故障公告】发布 .NET Core 版博客站点引起大量 500 错误

    非常抱歉,今天上午的博客站点故障给大家带来了很大的麻烦,请大家谅解.这次故障是我们发布 .NET Core 版博客站点引起的,虽然我们进行了充分的准备,但还是低估了高并发下的复杂问题. 以下是故障背景 ...

  8. 荔枝FM前端面试题

    最近接到了荔枝FM的面试通知,遗憾的是没有拿到offer,但是这次面试呢,还是收获很大的,下面就来给大家说说我遇到的面试题 一面 一面是直接发了一套面试题到邮箱,开启了防作弊的,限时20分钟做完,下面 ...

  9. 使用webstorm搭建vue-cli项目

    前言 随着vue在前端不断的壮大,越来越多的前端工程师使用vue了,作为大型项目的开发,vue-cli是不二之选,所以这篇博客是为搭建vue-cli所写,想要搭建vue-cli项目就必须先有git,n ...

  10. ccf 201903-3 损坏的RAID5

    9月份考ccf,暑假打算做一些往年的真题... 这个题,一开始真是把我给看晕了 传说中的大模拟,果然不简单QAQ 首先读懂题目就是一个大难点,特别是对于我这种题目一长就看不进去的人来说 读懂题目之后, ...