从一个新的角度去讨论如何实现多线程

我们要实现一个功能,开启一个线程打印HelloWorld

先说结论

 public static void main(String[] args) {
        new Thread(()-> System.out.println("HelloWorld\t" + Thread.currentThread().getName()),"MyHelloWorld").start();
 }

以上的代码我们实现的是:

  • 开启一个线程,将该线程名称命名为MyHelloWorld
  • 在线程中执行一条语句
  • 语句中打印HelloWorld,同时打印线程名称

以上代码简洁,并且语义充分。使用lambda表达式简化了线程的实现,并且给线程定义了线程名称,符合java规范的要求。

接下来,我们要来研究以下几点内容

  • 看看这样的实现,是怎么一步步得到的,
  • 这有什么好处

实现多线程的方式

首先,我们知道实现线程的几种方式中,有两种最传统的方式。
1、继承Thread类
2、实现Runnable接口
我们来看看这两种方式在代码上是如何写的。

1、继承Thread类

下面这段代码,在打印HelloWorld的时候,同时打印了当前线程的线程名称

class HellowWorldThread extends Thread{
    @Override
    public void run() {
        System.out.println("HelloWorld\t" + Thread.currentThread().getName());
    }
}

2、实现Runnable接口

下面这段代码,在打印HelloWorld的时候,也同时打印了当前线程的线程名称

class HelloWorldRunnable implements Runnable{
    @Override
    public void run() {
        System.out.println("HelloWorld\t"+ Thread.currentThread().getName());
    }
}

代码调用

在执行的时候,我们的代码是

 public static void main(String[] args) {
        new HellowWorldThread().start();
        new Thread(new HelloWorldRunnable()).start();
    }

传统写法的缺点

  • 需要额外写一个类
  • 如果要给线程命名,还需要再额外提供一个有参(可以传入线程名称)的构造函数
  • 业务和线程相耦合

如何优化

lambda表达式

我们知道Thread类中有个带参的构造方法,其中是需要传入一个实现Runnable接口的对象,同时传入一个线程名。
写法如下

    public static void main(String[] args) {
        new Thread(new Runnable() {
            @Override
            public void run() {
                System.out.println("HelloWorld\t" + Thread.currentThread().getName());
            }
        },"MyHelloWorldRunnableInnerClass").start();
    }

由于Runnable是 函数式接口
因此,根据lambda表达式的改造规则,我们可以将其改造成以下的形式(就是本文开始时候的样子)

 public static void main(String[] args) {
        new Thread(()-> System.out.println("HelloWorld\t" + Thread.currentThread().getName()),"MyHelloWorld").start();
 }

此时代码极大程度上,得到了简化。并且按照要求,还为线程提供了一个线程名称。

业务和线程耦合问题

在我们功能的实现过程中,是否需要考虑他是怎么运行的呢?我们当然可以考虑同步运行,也可以考虑并发运行。
开启一个线程,在线程中运行我们的业务代码,业务代码不需要考虑线程的问题

代码模型拆解

线程

    new Thread(
           //dosomthing'     
        ).start();

业务

此时的业务代码可以以任何姿势展现,不用考虑任何多线程问题。

    public void doBusiness(){
        //a lot of work 
    }

整合

  new Thread(
        ()-> doBusiness()
  ).start();

业务举例

我们要对订单进行处理,需要保存订单,通知扣减库存,通知扣费(业务上可能会更复杂)--这在OrderService中实现
我们的要多线程操作,加快处理速度。(思考OrderService需要继承Thread类吗,OrderService需要实现Runnable接口吗)
OrderService 的实现

class OrderService{
    public void saveOrder(){
    }
    public void  deductStock(){
    }
    public void charge(){
    }
}

业务执行的多个实现方案
1、在主线程外开启一个线程,在新开启的线程中,执行所有业务

 public static void order(){
        OrderService orderService = new OrderService();
        new Thread(
                ()->{
                    orderService.saveOrder();
                    orderService.deductStock();
                    orderService.charge();
                },"NewSingleThread"
        ).start();
    }

2、开启多个线程,保证每个线程自己独立运行

    public static void order2(){
        OrderService orderService = new OrderService();
        new Thread(()->orderService.saveOrder(),"saveOrderThread").start();
        new Thread(()->orderService.deductStock(),"deductStockThread").start();
        new Thread(()->orderService.charge(),"chargeThread").start();
    }

以上实现了两种方案,业务代码没有任何变动,我们还可以组合出多种多线程实现方案。

总结

我们在实现多线程的过程中,不要去继承或者实现Runnable类,使用new Thead(Runnable runnable,String threadName)去启动一个线程,其中Runnable接口则通过传入lambda表达式的方式,调用我们业务类的代码。以此做到线程实现和业务实现解耦合

你可能感兴趣的:(从一个新的角度去讨论如何实现多线程)