美文网首页
1.2 多线程 - 线程的创建

1.2 多线程 - 线程的创建

作者: Hey_Shaw | 来源:发表于2018-06-26 20:48 被阅读8次

每个线程的作用是完成一定的任务,实际就是执行一段程序流(一段顺序执行的代码)。Java使用线程执行体来代表这段程序流。

继承 Thread 类创建线程类

创建并启动多线程的步骤如下:

  • 1、定义 Thread 类的子类,并重写该类的 run() 方法,该 run() 方法的方法体就代表了线程需要完成的任务。因此把 run() 方法称为线程执行体
  • 2、创建 Thread 子类的实例,即创建了线程对象。
  • 3、调用线程对象的 start() 方法来启动该线程。

代码示例:

// 通过继承Thread类来创建线程类
public class FirstThread extends Thread { 
    private int i ;
    // 重写run方法,run方法的方法体就是线程执行体
    public void run() {
        for ( ; i < 100 ; i++ ){
            // 当线程类继承Thread类时,直接使用this即可获取当前线程
            // Thread对象的getName()返回当前该线程的名字
            // 因此可以直接调用getName()方法返回当前线程的名
            System.out.println(getName() +  " " + i);
        }
    }
    public static void main(String[] args){
        for (int i = 0; i < 100;  i++){
            // 调用Thread的currentThread方法获取当前线程
            System.out.println(Thread.currentThread().getName()
                +  " " + i);
            if (i == 20){
                // 创建、并启动第一条线程
                new FirstThread().start();
                // 创建、并启动第二条线程
                new FirstThread().start();
            }
        }
    }
}

Java 程序开始运行后,程序至少会创建一个主线程,主线程的线程执行体不是由 run() 方法确定的,而是由 main() 方法确定的 —— main() 方法的方法体代表主线程的线程执行体。

  • Thread.currentThread():currentThread() 是 Thread 类的静态方法,该方法总是返回当前正在执行的线程对象。
  • getName():该方法是 Thread 类的实例方法,该方法返回调用该方法的线程名字。
  • setName(String name):为线程设置名字,默认情况下:主线程的名字为main,用户启动的多个线程的名字依次为 Thread-0、Thread-1、Thread-n。

实现 Runnable 接口创建线程类

创建并启动多线程的步骤如下:

  • 1、定义 Runnable 接口的实现类,并重新该接口的 run() 方法,该 run() 方法的方法体同样是该线程的线程执行体。
  • 2、创建 Runnable 实现类的实例,并以此实例作为 Thread 的 target 来创建 Thread 对象,该 Thread 对象才是真正的线程对象。
  • 3、调用线程对象的 start() 方法来启动该线程。

代码示例:

// 通过实现Runnable接口来创建线程类
public class SecondThread implements Runnable {
    private int i ;
    // run方法同样是线程执行体
    public void run()   {
        for ( ; i < 100 ; i++ ) {
            // 当线程类实现Runnable接口时,
            // 如果想获取当前线程,只能用Thread.currentThread()方法。
            System.out.println(Thread.currentThread().getName()
                + "  " + i);
        }
    }

    public static void main(String[] args) {
        for (int i = 0; i < 100;  i++) {
            System.out.println(Thread.currentThread().getName()
                + "  " + i);
            if (i == 20) {
                SecondThread st = new SecondThread();     // ①
                // 通过new Thread(target , name)方法创建新线程
                new Thread(st , "新线程1").start();
                new Thread(st , "新线程2").start();
            }
        }
    }
}

Runnable 对象仅仅作为 Thread 对象的 target ,Runnable 实现类里包含的 run() 方法仅作为线程体。而实际的线程对象依然是 Thread 实例,只是该 Thread 线程负责执行其target 的 run() 方法。总结来说:FirstThread 直接创建的 Thread 子类即可代表线程对象;SecondThread 创建的 Runnable 对象只能作为线程对象的 target。
采用 Runnable 接口的方式创建的多个线程可以共享线程类的实例变量。

使用 Callable 和 Future 创建线程

Callable 接口提供了一个 call() 方法可以作为线程执行体:

  • call() 方法可以有返回值
  • call() 方法可以声明抛出异常

Callable 接口是Java5新增的接口,并不是 Runnable 接口的子接口,所以不能直接作为 Thread 的 target。call() 方法并不是直接调用,它是作为线程执行体被调用的。

Java5 提供了 Futurn 接口来代表 Callable 接口里 call() 的返回值,并为 Future 接口提供一个 FutureTask 实现类,该实现类实现了 Futurn 接口,并实现了 Runable 接口 —— 可以作为 Thread 类的 target 。

Futurn 接口里定义了如下方法来控制它关联的 Callable 任务

  • boolean cancel(boolean mayInterruptIfRunning):试图取消该 Future 里关联的Callable 任务。
  • V get():返回 Callable 任务里 call() 方法的返回值。调用该方法将导致程序阻塞,必须等到子线程结束后才会得到返回值。
  • V get(long timeout, TimeUnit unit):返回 Callable 任务里 call() 方法的返回值。该方法让程序最多阻塞 timeout 和 unit 指定的时间,如果经过指定时间后 Callable 任务依然没有返回值,将会抛出 TimeoutException 异常。
  • boolean isCancelled():如果在 Callable 任务正常完成前被取消,则返回 true 。
  • boolean isDone():如果 Callable 任务已完成,则返回 true 。

Callable 接口有泛型限制,Callable 接口里的泛型形参类型与 call() 方法返回值类型相同。

创建并启动有返回值的多线程的步骤如下:

  • 1、创建 Callable 接口的实现类,并实现 call() 方法将作为线程执行体,且该 call() 方法有返回值,再创建 Callable 实现类的实例。Java8 开始,可以直接使用 Lambda 表达式创建 Callable 对象。
  • 2、使用 FutureTask 类来包装 Callable 对象,该 FutureTask 对象封装了该 Callable 对象的 call() 方法的返回值。
  • 3、使用 FutureTask 对象作为 Thread 对象的 target 创建并启动新线程。
  • 4、调用 FutureTask 对象的 get() 方法来获得子线程执行结束后的返回值。

代码示例:

public class ThirdThread{
    public static void main(String[] args){
        // 创建Callable对象
        ThirdThread rt = new ThirdThread();
        // 先使用Lambda表达式创建Callable<Integer>对象
        // 使用FutureTask来包装Callable对象
        FutureTask<Integer> task = new FutureTask<Integer>((Callable<Integer>)() -> {
            int i = 0;
            for ( ; i < 100 ; i++ ){
                System.out.println(Thread.currentThread().getName()
                    + " 的循环变量i的值:" + i);
            }
            // call()方法可以有返回值
            return i;
        });
        for (int i = 0 ; i < 100 ; i++){
            System.out.println(Thread.currentThread().getName()
                + " 的循环变量i的值:" + i);
            if (i == 20){
                // 实质还是以Callable对象来创建、并启动线程
                new Thread(task , "有返回值的线程").start();
            }
        }
        try{
            // 获取线程返回值
            System.out.println("子线程的返回值:" + task.get());
        }
        catch (Exception ex){
            ex.printStackTrace();
        }
    }
}

创建线程的三种方式对比

  • 采用 Runnable、Callable 接口的方式创建多线程的优缺点:

    • 线程类只是实现了 Runnable 接口或 Callable 接口,还可以继承其他类。
    • 这种方式下,多个线程可以共享同一个 target 对象,所以非常适合多个相同线程来处理同一份资源的情况,从而可以将 CPU、代码和数据分开,形成清晰的模型,较好地体现了面向对象的思想。
    • 劣势是,编程稍稍复杂, 如果需要访问当前线程,则必须使用 Thread.currentThread() 方法。采用继承 Thread 类的方式创建多线程的优缺点。
  • 采用继承 Thread 类的方式创建多线程的优缺点:
    - 劣势是:线程类已经继承了 Thread 类,所以不能再继承其他父类。
    - 优势是:编写简单,如果需要访问当前线程,则无需使用 Thread.currentThread() 方法,直接使用 this 即可获得当前线程。

相关文章

  • Java基础(六)

    多线程 Java多线程并发 1.1 JAVA 并发知识库 1.2 JAVA 线程实现/创建方式 1.2.1 继承 ...

  • 多线程

    1.使用NSThread实现多线程 1.1.线程的创建 打印出这个 还有下面两种创建线程的方式 1.2由多线程引发...

  • 1.线程基础 -《多线程编程实战》

    1.线程基础 -《多线程编程实战》线程的生命周期,包括创建线程、挂起线程、线程等待,以及中止线程。 1.2 创建线...

  • 1.2 多线程 - 线程的创建

    每个线程的作用是完成一定的任务,实际就是执行一段程序流(一段顺序执行的代码)。Java使用线程执行体来代表这段程序...

  • 多线程

    创建一个多线程 创建多线程-继承线程类 创建多线程-实现Runnable接口 创建多线程-匿名类code

  • 10.3多线程详解

    Java高级-多线程 多线程创建 多线程通讯 线程池 1.多线程创建 thread/runnable图:继承Thr...

  • Python 多线程笔记

    Python 多线程笔记 创建线程 1. 使用函数创建多线程 2. 使用类创建多线程 继承 Thread 类 重写...

  • iOS性能篇——并行开发其实很简单

    概览 1.多线程 1.1 简介 1.2 iOS 多线程 2.NSThread 2.1 解决多线程阻塞问题 2.2 ...

  • iOS基础知识 (三)

    多线程 多线程创建方式 iOS创建多线程方式主要有NSThread、NSOperation、GCD,这三种方式创建...

  • 多线程 -- threading

    多线程模块 threading 创建多线程的两种方式:import threadingimport time 创建...

网友评论

      本文标题:1.2 多线程 - 线程的创建

      本文链接:https://www.haomeiwen.com/subject/cklmeftx.html