Java多线程(三)多线程实现方式

多线程有几种实现方式?如果被问到这个问题一定很头疼,因为百度一下随便就能出现各种各样的答案。两种、三种、四种、五种、六种、七种。。。

但本质上来讲,个人认为只有一种方式:实现Runnable接口。

先放个图:

 

线程相关类图.png

1、实现Runnable接口

public class DemoThreadTask implements Runnable{
    @Override
    public void run() {
        // TODO Auto-generated method stub
    }
    
    public static void main(String[] args) {
        DemoThreadTask task = new DemoThreadTask();
        Thread t = new Thread(task);
        t.start();
        ...
    }
}

实现Runnable接口,利用Runnable实例构造Thread,是较常用且最本质实现。此构造方法相当于对Runnable实例进行一层包装,在线程t启动时,调用Thread的run方法从而间接调用target.run():

public class Thread implements Runnable {
    /* What will be run. */
    private Runnable target;

    public void run() {
        if (target != null) {
            target.run();
        }
   }
     ...
}

2、继承Thread类

public class DemoThread extends Thread{
    @Override 
    //重写run方法
    public void run() {
        // TODO Auto-generated method stub
    }

    public static void main(String[] args) {
        DemoThread t = new DemoThread();
        t.start();
        ...
    }
}

这种实现方式是显示的继承了Thread,但从类图中我们可以看到,Thread类本身就继承自Runnable,所以继承Thread的本质依然是实现Runnable接口定义的run方法。

需要注意的是继承Thread方式,target对象为null,重写了run方法,导致方式1中的Thread原生的run方法失效,因此并不会调用到target.run()的逻辑,而是直接调用子类重写的run方法。

因为java是单根继承,此方式一般不常用。

3、实现Callable接口并通过FutureTask包装
先看demo:

public class DemoCallable implements Callable<String>{
    @Override
    public String call() throws Exception {
        // TODO Auto-generated method stub
        return null;
    }
    
    public static void main(String[] args) throws Exception {
        DemoCallable c = new DemoCallable();
        FutureTask<String> future = new FutureTask<>(c); 
        Thread t = new Thread(future);
        t.start();
        ...
        String result = future.get(); //同步获取返回结果
        System.out.println(result);
    }
}

实现Callable接口通过FutureTask包装,可以获取到线程的处理结果,future.get()方法获取返回值,如果线程还没执行完,则会阻塞。

这个方法里,明明没有看到run方法,没有看到Runnable,为什么说本质也是实现Runnable接口呢?

回看开篇的类图,FutureTask实现了RunnableFuture,RunnableFuture则实现了Runnable和Future两个接口。因此构造Thread时,FutureTask还是被转型为Runnable使用。因此其本质还是实现Runnable接口。

至于FutureTask的工作原理,后续篇章继续分析。

4、匿名内部类

匿名内部类也有多种变体,上述三种方式都可以使用匿名内部类来隐式实例化。

public class Demo{
    
    public static void main(String[] args) throws Exception {
        //方式一:Thread匿名内部类
        new Thread(){
            @Override
            public void run() {
                // TODO Auto-generated method stub
            }
        }.start();
        
        //方式二:Runnable匿名内部类
        new Thread(new Runnable() {
            @Override
            public void run() {
                // TODO Auto-generated method stub
            }
        }).start();
        
        ...
    }
}

匿名内部类的优点在于使用方便,不用额外定义类,缺点就是代码可读性差。

5、Lambda表达式

Lambda表达式是jdk8引入的,已不是什么新东西,现在都jdk10了。demo如下:

public class Demo{
    public static void main(String[] args) throws Exception {
        new Thread(() -> System.out.println("running") ).start() ;
        ...
    }
}

如此简洁的Lambda表达式,有没有吸引到你呢?当然本质不多说,还是基于Runnable接口。

6、线程池

public class DemoThreadTask implements Runnable{
    @Override
    public void run() {
        // TODO Auto-generated method stub
        System.out.println("running");
    }
    
    public static void main(String[] args) {
        DemoThreadTask task = new DemoThreadTask();
        ExecutorService ex = Executors.newCachedThreadPool();
        ex.execute(task);
        ...
    }
}

线程池与前面所述其他方式的区别在于执行线程的时候由ExecutorService去执行,最终还是利用Thread创建线程。线程池的优势在于线程的复用,从而提高效率。

关于线程池,后续篇章会继续详解。

7、定时器

public class DemoTimmerTask {

    public static void main(String[] args) throws Exception {
        Timer timer = new Timer();
        timer.scheduleAtFixedRate((new TimerTask() {
            @Override
            public void run() {
                System.out.println("定时任务1执行了....");
            }
        }), 2000, 1000);
    }
}

TimerTask的实现了Runnable接口,Timer内部有个TimerThread继承自Thread,因此绕回来还是Thread + Runnable。

总结,多线程的实现方式,在代码中写法千变万化,但其本质万变不离其宗。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值