二、Java-并发【多线程使用】

前言:

    前面一篇介绍了并发编程的一些是名词解释,并罗列了相关疑惑点。这篇将介绍在并发编程的实际应用

一、创建多线程的方式

概述:多线程创建的方式,有人说3种,有人说4种,其实具体数字并没有什么意义,在实际使用中,根据具体应用场景,选择合适的方式即可。下面介绍几种常见的多线程创建-使用方式

1、编写自己的任务类,继承Thread类,复写Thread类的run方法,在驱动线程中创建任务类的对象,调用start方法。将启动一个线程。执行该任务。

注意,这里强调编写自己的任务类,而不是编写自己的线程类,目的在于上一篇中说明的区分任务和线程的名词属性,避免混淆。

查看Thread的源码,其本质上是一个实现了Runnable接口的任务类

public
class Thread implements Runnable {
    /* Make sure registerNatives is the first thing <clinit> does. */
    private static native void registerNatives();
    ……

这种方式的使用

public class MyThread extends Thread {  
  public void run() {  
   System.out.println("MyThread run 方法开始执行");  
  }  
}  
 

// 在函数中执行下面代码,将启动线程执行任务
MyThread myThread1 = new MyThread();  
MyThread myThread2 = new MyThread();  
myThread1.start();  
myThread2.start();  

2、编写自己的任务类,实现Runnable接口。并创建该任务类的实例作为参数传递给Thread类的构造器,实例化一个Thread类实例,并调用start方法,启动一个线程。这种方式与继承Thread类的优点在于,接口可以多实现。Java中类的继承只能是单继承

public class MyThread implements Runnable {  
  public void run() {  
   System.out.println("MyThread.run  方法执行了");  
  }  
}  


// 在函数中执行如下代码
MyThread myThread = new MyThread();  
Thread thread = new Thread(myThread);  
thread.start();  

3、编写任务类,实现Callable接口,该方式的优点在于可以拿到线程执行的返回结果。

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.Random;
import java.util.concurrent.Callable;

/**
 * <p>Description: 定义任务-有返回值</p>
 * <p>Copyright: @2018</p>
 * <p>Company: YeePay</p>
 *
 * @author 小蚱蜢
 * @version V1.0 2018/6/10
 */
public class MyCallable implements Callable<String> {

    private static final Logger logger = LoggerFactory.getLogger(MyCallable.class);

    private int id;
    public MyCallable(int id){
        this.id = id;
    }

    // 定义线程执行体
    @Override
    public String call() throws Exception {
        // 这里模拟调用远程接口,做一些操作,返回时间大概在1-3s之间
        int sleepTime = getThreadSleepTime();
        Thread.sleep(sleepTime);
        logger.info("模拟调用接口,耗时时间:{}, 模拟调用接口返回结果#{}",sleepTime,id);

        return "模拟调用接口返回结果";
    }

    /**
     * 模拟任务执行耗费时间
     * @return
     */
    private int getThreadSleepTime(){
        Random random = new Random();
        int nextInt = random.nextInt(3);
        int sleepTime = 1000 * nextInt;
        return sleepTime;
    }

}


@Test
    public void test_MyCallable(){
        int taskCount = 1000000;

        // 假设每个任务耗时1秒钟,执行完10个任务,需要耗时10秒

        // 使用多线程调用
        long timeStart = System.currentTimeMillis();
        ExecutorService executorService = Executors.newCachedThreadPool();
        // ExecutorService executorService = Executors.newFixedThreadPool(10);
        List<Future<String>> futureResult = new ArrayList<Future<String>>();
        for (int i =0; i<taskCount ; i++){
            logger.info("开始执行任务:{}",i);
            Future<String> submitResult = executorService.submit(new MyCallable(i));
            futureResult.add(submitResult);
        }

        for (Future<String> sigleFuture : futureResult){
            logger.info("sigleFuture.isDone() :{}", sigleFuture.isDone());
            // if (sigleFuture.isDone()){
            //     try {
            //         logger.info("Future has finished task:{}", sigleFuture.get());
            //     } catch (InterruptedException e) {
            //         e.printStackTrace();
            //     } catch (ExecutionException e) {
            //         e.printStackTrace();
            //     }
            // }
            try {
                logger.info("task result :{}", sigleFuture.get());
            } catch (InterruptedException e) {
                e.printStackTrace();
            } catch (ExecutionException e) {
                e.printStackTrace();
            }
        }
        long endTime = System.currentTimeMillis();
        logger.info("使用多线程执行{}个任务,每个任务大概耗时1秒,最终耗费时间:{}",taskCount, ((endTime-timeStart)/ 1000.00));
    }

4、以上几种方式是显示的调用了Thread接口的start方法来驱动任务执行,更加常见的方式是通过线程池来管理,在上面Callable接口的例子中,通过Executors.newCachedThreadPool()来创建一个线程池。然后将任务类的实例提交给线程池,交由线程池来完成任务驱动。

以上四点是常见的线程使用方式。后面的章节中,将介绍线程池的具体配置,以及多线程编程中的一些常见问题,如果因为个人理解的偏差,文中若有不正确的地方,欢迎批评指正!

猜你喜欢

转载自blog.csdn.net/github_36433780/article/details/82291453