什么是多线程?多线程的作用、基础创建以及测试

346 阅读6分钟

什么是多线程

多线程是指在一个程序中同时运行多个线程(线程是指程序内的一个执行流),每个线程可以执行不同的任务。在多线程编程中,程序可以同时执行多个任务,而不是按照顺序逐个执行。多线程可以充分利用多核处理器的优势,提高程序的并发性和性能。

在多线程环境下,线程共享同一进程的内存空间,可以访问和修改共享的数据。线程之间可以进行通信和同步操作,通过线程间的消息传递和共享变量等机制,实现线程间的协作和数据交换。 多线程可以用于任务并行处理、提高程序的响应性和吞吐量,以及优化资源的利用等方面。然而,多线程编程也面临着线程安全、竞态条件等问题,需要仔细处理和管理共享数据的访问,以避免并发错误和数据不一致性的问题。

多线程的作用

在Java中,Stream(流)是一种用于处理集合数据的高级抽象概念。Java Stream API 提供了一种功能强大且表达力高的方式来处理数据集合,包括集合、数组等。使用Stream,可以更简洁、更具表达力地进行数据转换、过滤、映射、聚合等操作,同时还能利用多核处理器进行并行操作。以下是Java Stream 流的一些主要作用:

  1. 函数式风格的数据处理: 使用Stream,你可以以函数式风格处理数据,通过链式调用方法来进行各种数据操作。这使代码更易读、易于组合和重用。
  2. 数据转换和映射: Stream提供了map操作,可以将一个元素映射为另一个元素,从而进行数据转换。例如,可以将一个集合中的每个元素映射为另一种类型的元素。
  3. 数据过滤: 使用filter操作,可以根据特定条件筛选出符合条件的元素。这在从大型数据集中提取所需数据时非常有用。
  4. 数据聚合和归约: Stream提供了reduce操作,可以对集合中的元素进行归约操作,例如计算总和、最大值、最小值等。
  5. 并行处理: Stream可以通过并行操作,在多核处理器上同时处理数据,从而提高处理速度。通过parallelStream()方法,可以将Stream转换为并行流。
  6. 延迟执行: Stream中的操作通常是延迟执行的,即只有在终止操作(如forEachcollect)被调用时,才会实际开始执行操作。这使得Stream可以对操作进行优化,例如只计算实际需要的数据。
  7. 流水线操作: Stream允许将多个操作连接成流水线,每个操作依次应用于流中的元素。这种方式使得代码结构清晰,易于理解。
  8. 简化代码: 使用Stream可以大大减少需要编写的中间临时变量和循环代码,使代码更加简洁。

线程其实是程序中的一条执行路径

线程创建方式1

1.定义一个子类继承Thread类,并重写run方法

2.创建Thread的子类对象

3.调用start方法启动线程(启动线程后,会自动执行run方法中的代码)



/**
*1.  继Thread类型,就是一个自定义的线程类
*/
public class MyThread extends Thread{
    // 重号run 方法,写线程的执行任务
    @Override
    public void run() {
        for (int i = 0; i <= 5; i++) {
            System.out.println("子线程执行>"+i);
        }
    }
}

再定义一个测试类,在测试类中创建MyThread线程对象,并启动线程


public class ThreadTest1 {
    //目标: 掌握线程的创建方式一:继承Thread类
    // main方法是由一条默认的主线程负责执行。
    public static void main(String[] args) {
        // 3、创建MyThread线翟类的对象代表一个线翟
        MyThread myThread = new MyThread();

        // 4、start()方法: 启动线程(自动执行run方法的)
        myThread.start();

        for (int i = 0; i <= 5; i++) {
            System.out.println("主线程执行>"+i);

        }
    }
}

线程创建方式2

1.先写一个Runnable接口的实现类,重写run方法(这里面就是线程要执行的代码)

2.再创建一个Runnable实现类的对象

3.创建一个Thread对象,把Runnable实现类的对象传递给Thread

4.调用Thread对象的start()方法启动线程(启动后会自动执行Runnable里面的run方法)

/**
* 定义一个任务类,实现Runnable接口
*/
public class MyRunnable implements Runnable{
    //写子线程执行任务
    @Override
    public void run() {
        for (int i = 0; i <= 5; i++) {
            System.out.println("子线程MyRunnable执行>"+i);
        }
    }
}
/**
* 目标:掌握多线程创建二:实现Runnable接口
*/
public class ThreaTest {
    public static void main(String[] args) {
        //创建任务对象
        MyRunnable myRunnable = new MyRunnable();
        //把任务对象交给一个线程对象处理
        Thread thread = new Thread(myRunnable);
        thread.start();

        for (int i = 0; i <= 5; i++) {
            System.out.println("主线程ThreaTest执行>"+i);

        }
    }
}

线程创建方式2—匿名内部类

public class ThreadTest01 {
    public static void main(String[] args) {
        //掌握多线程创建方式二:匿名内部类写法

        //匿名内部类写法
        new Thread(new Runnable() {
            @Override
            public void run() {
                for (int i = 0; i <= 5; i++) {
                    System.out.println("子线程一执行>"+i);
                }
            }
        }).start();

        //lambda写法
        new Thread(() -> {
            for (int i = 0; i <= 5; i++) {
                System.out.println("子线程二执行>"+i);
            }
        }).start();

        for (int i = 0; i <= 5; i++) {
            System.out.println("主线程执行>"+i);
        }
    }
}

线程的创建方式3

  1. 先定义一个Callable接口的实现类,重写call方法
  2. 创建Callable实现类的对象
  3. 创建FutureTask类的对象,将Callable对象传递给FutureTask
  4. 创建Thread对象,将Future对象传递给Thread
  5. 调用Thread的start()方法启动线程(启动后会自动执行call方法)等call()方法执行完之后,会自动将返回值结果封装到FutrueTask对象中
  6. 调用FutrueTask对的get()方法获取返回结果
import java.util.concurrent.Callable;

public class MyCollable implements Callable<Integer> {

    @Override
    public Integer call() throws Exception {
        // 描述线程的任务,返回线程执行返回后的结果。
        // 需求:求1-n的和返回。
        int sum=0;
        for (int i = 1; i <= 100; i++) {
            sum=sum+i;
        }
        return sum;
    }
}
import java.util.concurrent.ExecutionException;
import java.util.concurrent.FutureTask;

public class CallableTest {
    public static void main(String[] args) throws ExecutionException, InterruptedException {
        // 3、创建一个Callable的对象
        MyCollable myCollable = new MyCollable();

        // 4、把Callable的对象封装成一个FutureTask对象(任务对象)
        // 未来任务对象的作用?
        // 1、是一个任务对象,实现了Runnable对象.
        // 2、可以在线程执行完毕之后,用未来任务对象调用get方法获取线程执行完毕后的结果。
        FutureTask<Integer> ift = new FutureTask<Integer>(myCollable);

        // 5、把任务对象交给一个Thread对象
        Thread thread = new Thread(ift);
        thread.start();

        // 6、获取线程执行完毕后返回的结果。
        // 注意:如果执行到这儿,假如上面的线程还没有执行完毕
        // 这里的代码会暂停,等待上面线程执行完毕后才会获取结果。
        Integer integer = ift.get();
        System.out.println("相加得到的值为:"+integer);
    }
}

多线程多个线程测试

用 BigDecimal 写 累加和

import java.math.BigDecimal;
import java.util.concurrent.Callable;

public class BigDecimalTest implements Callable<BigDecimal> {
    private int start;
    private int end;

    public BigDecimalTest(int start, int end) {
        this.start = start;
        this.end = end;
    }

    @Override
    public BigDecimal call() throws Exception {
        BigDecimal sum = BigDecimal.valueOf(0);
        for (int i = start; i <= end; i++) {
            sum = sum.add(BigDecimal.valueOf(i));
        }
        return sum;
    }
}
import java.math.BigDecimal;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.FutureTask;

public class Test010 {
    public static void main(String[] args) throws ExecutionException, InterruptedException {

        //        BigDecimalTest bd1 = new BigDecimalTest(1,200);
        //        FutureTask<BigDecimal> ift1 = new FutureTask<>(bd1);
        //        Thread thread = new Thread(ift1);
        //        thread.start();
        //
        //        BigDecimalTest bd2 = new BigDecimalTest(201,400);
        //        FutureTask<BigDecimal> ift2 = new FutureTask<>(bd2);
        //        Thread thread2 = new Thread(ift2);
        //        thread2.start();
        //
        //        BigDecimalTest bd3 = new BigDecimalTest(401,600);
        //        FutureTask<BigDecimal> ift3 = new FutureTask<>(bd3);
        //        Thread thread3 = new Thread(ift3);
        //        thread3.start();
        //
        //        BigDecimalTest bd4 = new BigDecimalTest(601,800);
        //        FutureTask<BigDecimal> ift4 = new FutureTask<>(bd4);
        //        Thread thread4 = new Thread(ift4);
        //        thread4.start();
        //
        //        BigDecimalTest bd5 = new BigDecimalTest(801,1000);
        //        FutureTask<BigDecimal> ift5 = new FutureTask<>(bd5);
        //        Thread thread5 = new Thread(ift5);
        //        thread5.start();
        //
        //        BigDecimal sum1 = ift1.get();
        //        BigDecimal sum2 = ift2.get();
        //        BigDecimal sum3 = ift3.get();
        //        BigDecimal sum4 = ift4.get();
        //        BigDecimal sum5 = ift5.get();
        //        System.out.println("累加和为:"+(sum1.add(sum2).add(sum3).add(sum4).add(sum5).toString()));

        BigDecimal sum1 = processSum(1, 200000);
        BigDecimal sum2 = processSum(200001, 400000);
        BigDecimal sum3 = processSum(400001, 600000);
        BigDecimal sum4 = processSum(600001, 800000);
        BigDecimal sum5 = processSum(800001, 1000000);
        String s = sum1.add(sum2).add(sum3).add(sum4).add(sum5).toString();
        System.out.println("程序运行结果为:" + s);
    }

    public static BigDecimal processSum(int start, int end) throws ExecutionException, InterruptedException {
        BigDecimalTest bd = new BigDecimalTest(start, end);
        FutureTask<BigDecimal> ift = new FutureTask<>(bd);
        Thread thread = new Thread(ift);
        thread.start();
        return ift.get();
    }
}