您的位置 首页 java

「java实战系列」多线程开发|基础篇|第一讲

为什么要使用 多线程 ?在 Java 开发中,多线程并发是比较常见的业务场景。比如一些费时任务的处理(如:上百万数据的处理)这个时候就需要使用多线程处理。但是多线程是一把双刃剑,用得好,代码数据处理能力也能得到大幅提升。用得不好,可能会带来灾难性的后果(如:服务器资源耗尽,造成服务宕机)。下面就从实战的角度出发,探讨一下如何正确使用多线程。

一、java开发中实现多线程方式有哪些

1、继承 Thread 类,重写run()方法

2、实现Runnable接口,重写run()方法

3、实现Callable接口,重写call()方法 并使用FutureTask获取call( )方法的返回结果

4、 通过 线程池 创建 线程

下面我们用代码示例来实现前三种写法:

 package com.example.jacob.thread;

/**
 * 利用Thread类实现多线程
 * @author yangzheng
 * @create 2022-05-28
 */
public class ThreadCreateByThreadClass {

    public  static   void  main(String[] args) {
        //创建第一个子线程
        JacobThread firstThread = new JacobThread();
        firstThread.start();
        String firstThreadName = firstThread.getName();
        System.out.println("firstThreadName =" + firstThreadName);
        //创建第二个子线程
        JacobThread secondThread = new JacobThread();
        secondThread.start();
        String secondThreadName = secondThread.getName();
        System.out.println("secondThreadName =" + secondThreadName);
    }
}

/**
 * JacobThread 继承 Thread类
 */
class JacobThread  extends  Thread {
    @Override
    public void run() {
        super.run();
        //获取线程名称
        String threadName = Thread.currentThread().getName();
        for (int i = 0; i < 3; i++) {
            System.out.println(threadName + ",i=" + i);
        }
    }
}
  

运行结果如下:

 firstThreadName =Thread-0
Thread-0,i=0
Thread-0,i=1
Thread-0,i=2
secondThreadName =Thread-1
 Thread- 1,i=0
Thread-1,i=1
Thread-1,i=2  

 package com.example.jacob.thread;

/**
 * 利用Runnable接口实现多线程
 * 主要步骤
 * 1、创建Runnable接口实现类并重写该接口的run( )方法
 * 2、创建Runnable接口实现类对象
 * 3、利用Thread有参构造函数public Thread(Runnable target)和Runnable接口实现类对象创建线程实例
 * 4、调用线程实例的start( )方法启动线程
 * @author yangzheng
 * @create 2022-05-28
 */
public class ThreadCreateByInterface {
    public static void main(String[] args) {
        // 创建第一个子线程
        JacobRunnable firstMyRunnable=new JacobRunnable();
        Thread firstThread = new Thread(firstMyRunnable);
        firstThread.start();
        String firstThreadName = firstThread.getName();
        System.out.println("firstThreadName=" + firstThreadName);
        // 创建第二个子线程
        JacobRunnable secondMyRunnable=new JacobRunnable();
        Thread secondThread = new Thread(secondMyRunnable);
        secondThread.start();
        String secondThreadName = secondThread.getName();
        System.out.println("secondThreadName="+ secondThreadName);
    }
}


/**
 * MyRunnable实现Runnable接口
 */
class JacobRunnable implements Runnable {
    @Override
    public void run() {
        String threadName = Thread.currentThread().getName();
        for (int i = 0; i < 3; i++) {
            System.out.println(threadName + "i=" + i);
        }

    }

}
  

运行结果如下

 firstThreadName=Thread-0
secondThreadName=Thread-1
Thread-0i=0
Thread-0i=1
Thread-0i=2
Thread-1i=0
Thread-1i=1
Thread-1i=2  

 package com.example.jacob.thread;

import java.util.concurrent.Callable;
import java.util.concurrent.Execution Exception ;
import java.util.concurrent.FutureTask;

/**
 * 利用Runnable接口实现多线程
 * 主要步骤
 1、创建Callable接口实现类并重写该接口的call( )方法\
 2、创建Callable接口实现类对象
 3、使用Runnable子类FutureTask的有参构造函数public FutureTask(Callable< V > callable)和Callable接口实现类对象创建FutureTask实例
 4、利用Thread有参构造函数public Thread(Runnable target)和FutureTask实例创建线程实例
 5、调用线程实例的start( )方法启动线程
 6、利用FutureTask的get( )方法获取子线程执行结果
 * @author yangzheng
 * @create 2022-05-28
 */
public class ThreadCreateByCallable {

    public static void main(String[] args) throws ExecutionException, InterruptedException {
        // 创建第一个子线程
        JacobCallable firstMyCallable = new JacobCallable();
        FutureTask firstFutureTask = new FutureTask<>(firstMyCallable);
        Thread firstThread = new Thread(firstFutureTask);
        firstThread.start();
        String firstThreadName = firstThread.getName();
        System.out.println("firstThreadName="+ firstThreadName);
        // 获取第一个子线程返回的结果
        Object firstThreadResult = firstFutureTask.get();
        System.out.println("firstThreadResult="+ firstThreadResult);
        // 创建第二个子线程
        JacobCallable secondMyCallable = new JacobCallable();
        FutureTask secondFutureTask = new FutureTask<>(secondMyCallable);
        Thread secondThread = new Thread(secondFutureTask);
        secondThread.start();
        String secondThreadName = secondThread.getName();
        System.out.println("secondThreadName=" + secondThreadName);
        // 获取第二个子线程返回的结果
        Object secondThreadResult = secondFutureTask.get();
        System.out.println("secondThreadResult=”" + secondThreadResult);

    }
}

/**
 * MyCallable实现Callable接口
 */
class JacobCallable implements Callable {
    @Override
    public Object call() throws Exception {
        String threadName = Thread.currentThread().getName();
        int i = 0;
        while (i < 3) {
            System.out.println(threadName + ", i ="+ i);
            i++;

        }
        return i;
    }
}
  
 firstThreadName=Thread-0
Thread-0, i =0
Thread-0, i =1
Thread-0, i =2
firstThreadResult=3
secondThreadName=Thread-1
Thread-1, i =0
Thread-1, i =1
Thread-1, i =2
secondThreadResult=”3  

二、线程池创建多线程

线程池: 从本质上来讲, 就是⼀个容器,⾥⾯存储了若⼲个线程。

解决问题 :最主要是解决线程复⽤的问题。当执行线程时,不需要频繁的对线程进行新建和销毁,减少了 CPU 的负担。当需要一个线程时,不需要实例化,去线程池中查看是否有闲置的线程可以使用。如果有,则直接使用;如果没有,再去按照策略实例化新的线程。并且当线程使用完毕时,并不是马上销毁,而是根据配置策略判断是否需要放到线程池中,以便下次使用。

线程池中的所有线程可以分成两个部分:“核心线程”和”临时线程”

核心线程:核⼼线程一直存在于线程池中。当线程池销毁时,核心线程才会被销毁。

临时线程:临时新增线程,在处理完⾃⼰需要处理的任务后, 如果没有其他的任务要处理,就会空闲。当空闲的时间到达了指定的时间之后,这个临时线程就会被销毁。

java创建线程池可以分为 手动创建 自动创建 两种模式,

1、自动创建主要使用 Executors工具类。

Executors类的new方法

2、 手动创建主要用 ThreadPoolExecutor 类,体现在可以灵活设置线程池的各个参数,体现在代码中即ThreadPoolExecutor类构造器上各个实参的不同:

本篇文章对线程池不做过多概述,后续文章再做详细介绍。

总结:

因为没有类的单继承的局限性,开发当中优先选择实现Runnable接口的方式来启动多线程

文章来源:智云一二三科技

文章标题:「java实战系列」多线程开发|基础篇|第一讲

文章地址:https://www.zhihuclub.com/189059.shtml

关于作者: 智云科技

热门文章

发表回复

您的电子邮箱地址不会被公开。

网站地图