2、线程的创建

来源:互联网 发布:淘宝开学季什么时候 编辑:程序博客网 时间:2024/06/09 19:19

线程的创建

Java 提供了三种创建线程的方法:
- 通过实现 Runnable 接口;
- 通过继承 Thread 类本身;
- 通过 Callable 和 Future 创建线程。

我们将使用第二种方法来制作一个简单的程序,它能创建和运行10个线程。每一个线程能计算和输出1-10以内的乘法表。

通过实现 Runnable 接口来创建线程

创建一个名为Calculator的类,这个类要实现Runnable接口。

package com.lf.base.creat;/** * Created by LF on 2017/5/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);        }    }}

重写该方法,重要的是理解的 run() 可以调用其他方法,使用其他类,并声明变量,就像主线程一样。
在创建一个实现 Runnable 接口的类之后,你可以在类中实例化一个线程对象。


通过继承Thread来创建线程

创建一个线程的第二种方法是创建一个新的类,该类继承 Thread 类,然后创建一个该类的实例。
继承类必须重写 run() 方法,该方法是新线程的入口点。它也必须调用 start() 方法才能执行。
该方法尽管被列为一种多线程实现方式,但是本质上也是实现了 Runnable 接口的一个实例。

public class MyThread extends Thread {    private int number;    public MyThread(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);        }    }}

通过 Callable 和 Future 创建线程

  1. 创建 Callable 接口的实现类,并实现 call() 方法,该 call() 方法将作为线程执行体,并且有返回值。
  2. 创建 Callable 实现类的实例,使用 FutureTask 类来包装 Callable 对象,该 FutureTask 对象封装了该 Callable 对象的 call() 方法的返回值。
  3. 使用 FutureTask 对象作为 Thread 对象的 target 创建并启动新线程。
  4. 调用 FutureTask 对象的 get() 方法来获得子线程执行结束后的返回值。
public class MyCallable implements Callable<Integer> {    public static void main(String[] args) {        FutureTask<Integer> futureTask = new FutureTask<>(new MyCallable());        for (int i = 0; i < 100; i++) {            System.out.println(Thread.currentThread().getName() + " 的循环变量i的值" + i);            if (i == 20) {                new Thread(futureTask, "有返回值的线程").start();            }        }    }    @Override    public Integer call() throws Exception {        int i = 0;        int size = 100;        for (; i < size; i++) {            System.out.println(Thread.currentThread().getName() + " " + i);        }        return i;    }}

每个Java程序最少有一个执行线程。当你运行程序的时候, JVM运行负责调用main()方法的执行线程。

当调用Thread对象的start()方法时, 我们创建了另一个执行线程。在这些start()方法调出后,我们的程序就有了多个执行线程。

当全部的线程执行结束时(更具体点,所有非守护线程结束时),Java程序就结束了。如果初始线程(执行main()方法的主线程)运行结束,其他的线程还是会继续执行直到执行完成。但是如果某个线程调用System.exit()指示终结程序,那么全部的线程都会结束执行。

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

线程的属性

Thread类的对象中保存了一些属性信息能够帮助我们来辨别每一个线程,知道它的状态,调整控制其优先级。 这些属性是:
- ID: 每个线程的独特标识。
- Name: 线程的名称。
- Priority: 线程对象的优先级。优先级别在1-10之间,1是最低级,10是最高级。不建议改变它们的优先级,但是你想的话也是可以的。
- Status: 线程的状态。在Java中,线程只能有这6种中的一种状态: new, runnable, blocked, waiting, time waiting, 或 terminated.
Thread 类有能保存使用线程信息的属性。JVM根据线程的优先级来选择将使用CPU的线程,然后再根据每个线程的情况来实现它们的状态。

如果你没有声明一个线程的名字,那么JVM会自动命名它为:Thread-XX,XX是一个数字。线程的ID或者状态是不可修改的。Thread类没有实现setId()和setStatus()方法来允许修改它们。

你可以用Thread类的静态方法currentThread()来访问正在运行的Runnable 对象的 Thread对象。

Thread和Runnable的异同点

Thread 和 Runnable 的相同点:都是“多线程的实现方式”。
Thread 和 Runnable 的不同点:
- Thread 是类,而Runnable是接口;
- Thread本身是实现了Runnable接口的类。我们知道“一个类只能有一个父类,但是却能实现多个接口”,因此Runnable具有更好的扩展性。
此外,Runnable还可以用于“资源的共享”。即,多个线程都是基于某一个Runnable对象建立的,它们会共享Runnable对象上的资源。
通常,建议通过“Runnable”实现多线程!

start() 和 run()的区别说明

start() : 它的作用是启动一个新线程,新线程会执行相应的run()方法。start()不能被重复调用。
run() : run()就和普通的成员方法一样,可以被重复调用。单独调用run()的话,会在当前线程中执行run(),而并不会启动新线程!