多线程-01-创建线程的三种方式

简介: 多线程创建线程的三种方式进程和线程几乎所有的操作系统都支持同时运行多个任务,一个任务通常就是一个程序,每个运行中的程序就是一个进程Process。当一个程序运行时,内部可能包含多个顺序执行流,每个顺序执行流就是一个线程Thread。

多线程<small>创建线程的三种方式</small>

进程和线程

几乎所有的操作系统都支持同时运行多个任务,一个任务通常就是一个程序,每个运行中的程序就是一个进程Process。当一个程序运行时,内部可能包含多个顺序执行流,每个顺序执行流就是一个线程Thread。

线程是进程的组成部分,一个进程可以拥有多个线程,一个线程必须拥有一个父进程。
线程可以拥有自己的堆栈,自己的程序计数器和自己的局部变量,但是线程不拥有自己的资源。它与父进程的其他线程共享该进程的所有资源。
线程的执行是抢占式的,所以任何一个线程都有可能被挂起,以便另外一个线程的执行。
线程可以创建和撤销另外一个线程。

线程共享的环境包括:进程的代码段,进程的共有数据等。利用这些共享的数据,线程很容易实现项目之间的通信。

1. 继承Thread类创建线程类

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

currenThread(),获取当前线程对象
getName(),当前线程的名字,默认是main ,Thread-0,Thread-1,Thread-n

package com.manyThread;

/**
 * @author futao
 * Created on 18-1-8-下午8:49.
  * 多线程的实现方式1,继承Thread类,重写run()方法
 */
public class FirstThread extends Thread {
    private int i;

    @Override
    public void run() {
        for (; i < 1000; i++) {
            System.out.println("==" + this.getName() + " " + i);
        }
    }

    public static void main(String[] args) {
        for (int i = 0; i < 1000; i++) {
            System.out.println("main===" + Thread.currentThread().getName() + "    " + i);
            if (i == 20) {
                FirstThread firstThread = new FirstThread();
                firstThread.setName("Niu");
                firstThread.start();

                new FirstThread().start();
            }
        }
    }
}

可以发现,i的值是不连续的,所以用继承Thread的方式实现的多线程是不能够共享线程的实例变量的。
使用继承Thread类的方法来创建线程时,多个线程之间无法共享线程的实例变量,因为每个线程都需要实例化一个对象。

2. 实现Runnable接口创建线程类

  1. 定义Runnable接口的实现类,并重写该接口的run()方法,该run()方法的方法体同样是该线程的线程执行体。
  2. 创建Runnable实现类的实例,并以此实例作为Thread的target来创建Thread对象,该Thread对象才是真的线程对象。
package com.manyThread;

/**
 * @author futao
 * Created on 18-1-8-下午9:10.
 * 多线程的实现方式2,实现Runnable接口,重写run()方法
 */
public class FirstRunnable implements Runnable {
    private int i;

    @Override
    public void run() {
        for (; i < 1000; i++) {
            System.out.println(Thread.currentThread().getName() + "===" + i);
        }
    }

    public static void main(String[] args) {


        for (int j = 0; j < 100; j++) {
            System.out.println("main" + j);
            if (j == 20) {
                FirstRunnable firstRunnable = new FirstRunnable();
                /*Runnable的实现类的对象仅仅用来作为new Thread()的target*/
                Thread thread = new Thread(firstRunnable, "myNewThread");
                thread.start();

                Thread thread1 = new Thread(firstRunnable, "2thread");
                thread1.start();

            }
        }
    }
}

变量 i 的值是连续的,所以通过实现Runnable接口的方式实现的多线程是可以共享线程类的实例变量的
这是因为在这种方式下,程序所创建的Runnable对象只是线程的target,而多个线程可以共享同一个target,所以多个线程可以共享同一个线程类(实际上是线程的target类)的实例变量。
所以通过实现Runnable接口创建的多线程时,Thread类的作用就是把run()方法包装成线程执行体。

3.使用Callable和Future创建线程

Runnable接口的增强版

  1. 创建Callable接口的实现类,并实现call()方法,作为线程的执行体,且该call()方法有返回值,可以直接使用Lambda表达式创建Callable对象
  2. 使用FutureTask类来包装Callable对象,该FutureTask对象封装了该Callable对象的call()方法的返回值。
  3. 使用FutureTask对象作为Thread对象的target创建并且启动线程
  4. 调用FutureTask对象的get()方法来获得子线程执行之后的返回值。(将导致主线程被阻塞,直到call()方法返回返回值)
package com.manyThread;

import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.FutureTask;

/**
 * @author futao
 * Created on 18-1-11-上午10:21.
 */
public class FirstCallable implements Callable {
    @Override
    public Object call() throws Exception {
        return 6666;
    }

    public static void main(String[] args) {
//        FirstCallable firstCallable = new FirstCallable();
//        FutureTask futureTask = new FutureTask(firstCallable);
//        Thread thread = new Thread(futureTask);
//        thread.start();
//        try {
//            System.out.println(futureTask.get());
//        } catch (InterruptedException e) {
//            e.printStackTrace();
//        } catch (ExecutionException e) {
//            e.printStackTrace();
//        }


        FutureTask futureTask1 = new FutureTask(() -> {
            int i = 0;
            for (; i <= 100; i++) {
                System.out.println(Thread.currentThread().getName() + i);
            }
            return i;
        });
        for (int i = 0; i < 50; i++) {
            System.out.println(Thread.currentThread().getName() + i);
            if (i == 20) {
                Thread thread = new Thread(futureTask1);
                thread.start();
                try {
                    /*get()方法将导致主线程被阻塞,直到call()方法结束并返回返回值为止*/
                    System.out.println(futureTask1.get());
                } catch (InterruptedException e) {
                    e.printStackTrace();
                } catch (ExecutionException e) {
                    e.printStackTrace();
                }
            }

        }

    }
}

4. 创建线程的三种方式比较

img_6c636426742274a30dba40b4916c82b6.jpe
0
目录
相关文章
|
2天前
|
NoSQL Redis
单线程传奇Redis,为何引入多线程?
Redis 4.0 引入多线程支持,主要用于后台对象删除、处理阻塞命令和网络 I/O 等操作,以提高并发性和性能。尽管如此,Redis 仍保留单线程执行模型处理客户端请求,确保高效性和简单性。多线程仅用于优化后台任务,如异步删除过期对象和分担读写操作,从而提升整体性能。
12 1
|
2月前
|
存储 消息中间件 资源调度
C++ 多线程之初识多线程
这篇文章介绍了C++多线程的基本概念,包括进程和线程的定义、并发的实现方式,以及如何在C++中创建和管理线程,包括使用`std::thread`库、线程的join和detach方法,并通过示例代码展示了如何创建和使用多线程。
60 1
|
2月前
|
Java 开发者
在Java多线程编程中,创建线程的方法有两种:继承Thread类和实现Runnable接口
【10月更文挑战第20天】在Java多线程编程中,创建线程的方法有两种:继承Thread类和实现Runnable接口。本文揭示了这两种方式的微妙差异和潜在陷阱,帮助你更好地理解和选择适合项目需求的线程创建方式。
32 3
|
2月前
|
Java 开发者
在Java多线程编程中,选择合适的线程创建方法至关重要
【10月更文挑战第20天】在Java多线程编程中,选择合适的线程创建方法至关重要。本文通过案例分析,探讨了继承Thread类和实现Runnable接口两种方法的优缺点及适用场景,帮助开发者做出明智的选择。
25 2
|
2月前
|
Java
Java中多线程编程的基本概念和创建线程的两种主要方式:继承Thread类和实现Runnable接口
【10月更文挑战第20天】《JAVA多线程深度解析:线程的创建之路》介绍了Java中多线程编程的基本概念和创建线程的两种主要方式:继承Thread类和实现Runnable接口。文章详细讲解了每种方式的实现方法、优缺点及适用场景,帮助读者更好地理解和掌握多线程编程技术,为复杂任务的高效处理奠定基础。
41 2
|
2月前
|
Java 开发者
Java多线程初学者指南:介绍通过继承Thread类与实现Runnable接口两种方式创建线程的方法及其优缺点
【10月更文挑战第20天】Java多线程初学者指南:介绍通过继承Thread类与实现Runnable接口两种方式创建线程的方法及其优缺点,重点解析为何实现Runnable接口更具灵活性、资源共享及易于管理的优势。
47 1
|
2月前
|
安全 Java 开发者
Java多线程中的`wait()`、`notify()`和`notifyAll()`方法,探讨了它们在实现线程间通信和同步中的关键作用
本文深入解析了Java多线程中的`wait()`、`notify()`和`notifyAll()`方法,探讨了它们在实现线程间通信和同步中的关键作用。通过示例代码展示了如何正确使用这些方法,并分享了最佳实践,帮助开发者避免常见陷阱,提高多线程程序的稳定性和效率。
53 1
|
2月前
|
Java
在Java多线程编程中,`wait()` 和 `notify()/notifyAll()` 方法是线程间通信的核心机制。
在Java多线程编程中,`wait()` 和 `notify()/notifyAll()` 方法是线程间通信的核心机制。它们通过基于锁的方式,使线程在条件不满足时进入休眠状态,并在条件成立时被唤醒,从而有效解决数据一致性和同步问题。本文通过对比其他通信机制,展示了 `wait()` 和 `notify()` 的优势,并通过生产者-消费者模型的示例代码,详细说明了其使用方法和重要性。
40 1
|
1月前
|
数据采集 Java Python
爬取小说资源的Python实践:从单线程到多线程的效率飞跃
本文介绍了一种使用Python从笔趣阁网站爬取小说内容的方法,并通过引入多线程技术大幅提高了下载效率。文章首先概述了环境准备,包括所需安装的库,然后详细描述了爬虫程序的设计与实现过程,包括发送HTTP请求、解析HTML文档、提取章节链接及多线程下载等步骤。最后,强调了性能优化的重要性,并提醒读者遵守相关法律法规。
63 0
|
2月前
|
存储 前端开发 C++
C++ 多线程之带返回值的线程处理函数
这篇文章介绍了在C++中使用`async`函数、`packaged_task`和`promise`三种方法来创建带返回值的线程处理函数。
82 6