java的多线程创建方法与其内部如何实现的?

目录

1,继承Thread类,重写run方法

(1)代码的实现如下

(2)重写run()方法和调用start()方法分析

 2,实现Runnable接口,并重写run方法

(1)代码的实现如下:

(2)如何实现的?

3,实现Callable接口,重写call()方法

(1)代码实现如下:

(2)如何实现的?

总结


1,继承Thread类,重写run方法


(1)代码的实现如下

package com.lzm.multithreading;

public class MultithreadingApplication extends Thread{

    @Override
    public void run(){
        System.out.println("我是线程" + Thread.currentThread().getName());
    }

    public static void main(String[] args) {
        MultithreadingApplication abc1 = new MultithreadingApplication();
        MultithreadingApplication abc2 = new MultithreadingApplication();
        abc1.start();
        abc2.start();
    }
}

(2)重写run()方法和调用start()方法分析


为什么要重写run方法?从代码中我们可以看到run方法就是我们线程运行的处理部分的入口,我们看一下源码。
首先我们查看run()方法在Thread类中的位置,如下图,注释字段说了,如果这个对象是通过Runable创建的,则运行这个线程调用run方法,并且注明Thread的子类要重写这个run方法。

 我们在启动线程的时候应该是调用start(),然后执行run()方法,为什么会这样呢?直接调用run()方法难道不行么?

所以我们可以将主程序中的代码简单改一下,如下:

 然后对比一下两次的结果:

左图执行start()方法, 右图执行run()方法,经过简单比对,我们可以看出,直接执行run()方法,实际上还是采用的主线程顺序执行的方式,并没有实现线程并发执行的情况。而调用start()方法则是重新创建了一个新的线程并执行其run()方法。

我们可以简单看一下start()方法的源码:如下图,实际上主要执行的源码时start0()方法,而该方法是native修饰,意味着调用的不是java代码,如果对start0()感兴趣,可以下载OpenJDK去研究一下,就是在运行时,虚拟机重新创建了个线程来运行该程序。

 2,实现Runnable接口,并重写run方法

(1)代码的实现如下:

package com.lzm.multithreading;

import java.util.concurrent.Callable;

public class MultithreadingApplication implements Runnable{

    @Override
    public void run(){
        System.out.println("我是线程" + Thread.currentThread().getName());
    }

    public static void main(String[] args) {
        MultithreadingApplication abc1 = new MultithreadingApplication();
        MultithreadingApplication abc2 = new MultithreadingApplication();
        Thread t1 = new Thread(abc1);
        Thread t2 = new Thread(abc2);
        t1.start();
        t2.start();
    }
}

(2)如何实现的?

如上代码所示,可以看出,实际上实现Runnable接口和Thread类的不同就在于,实现Runnable接口需要实例化Thread类对象,然后在启动。

我们可以看一下源码,首先看一下实现的Runnable接口,如下图,注释中说明了,启动线程会回调这个对象的run()代码。也就是说,实现这个接口也是通过run()方法作为处理的入口。

 其次,在第一部分说到直接调用run()方法,实际上还是在主线程中依次执行。那么实现了Runnable接口,怎么来调用呢?

还是与Thread类结合,我们可以看类中的一个有参构造函数如下图:注释中说明了,运行时调用target对象的run()方法。而target对象就是Runnable对象,所以我们通过传入一个Runnable对象,来实现线程对象的构造。然后调用start()方法在JVM中创建线程并执行run()方法。

3,实现Callable接口,重写call()方法

(1)代码实现如下:

package com.lzm.multithreading;

import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.FutureTask;

public class MultithreadingApplication implements Callable<String>{

    @Override
    public String call() throws Exception {
        System.out.println("我是线程" + Thread.currentThread().getName());
        return "SUCCESS";
    }

    public static void main(String[] args) {
        MultithreadingApplication abc1 = new MultithreadingApplication();
        FutureTask<String> f1 = new FutureTask<String>(abc1);
        FutureTask<String> f2 = new FutureTask<String>(abc1);
        Thread t1 = new Thread(f1);
        Thread t2 = new Thread(f2);
        t1.start();
        t2.start();
        try {
            String rst = f1.get();
            System.out.println(t1.getName() + " : " + rst);
            String rst2 = f2.get();
            System.out.println(t2.getName() + " : " + rst2);
        } catch (InterruptedException e) {
            e.printStackTrace();
        } catch (ExecutionException e) {
            e.printStackTrace();
        }
    }
}

(2)如何实现的?


首先说一下,实现Callable接口,和上述其他两种的差别,Callable接口会返回相应的值并抛出异常。并且java.util.concurrent这个包是并发包,也就是并发的很多东西包含其中。

其次我们从代码本身出发,首先看一下Callable接口中的内容,如下图所示。我们从注释中可以看到,他说这个接口和Runnable都是为线程执行的类设计的,但是它有返回值和抛出异常。

我们在上述内容中使用的是FutureTask来提交对象并接收返回值。FutureTask是Future接口的实现类,所以先来看一下FutureTask类是如何构造的,如下图中注释的说明,说它可以用于包装Callable和Runnable对象,将其交给线程执行。

 接着上述简单看一下,FutureTask实现RunnableFuture接口,而他又继承了Runable和Future接口对象,所以FutureTask可以对Runnable对象进行包装,并且其中也创建了包含Callable的构造函数。

 如果对FutureTask类有兴趣,可以进一步探究。

总结

上述三种方法是常用的java的三种创建多线程的方法,但是线程对于共享资源的使用如果不加限制就会出现脏读、幻读、不可重复读的情况,以及线程之间的通信有许多种方式。我在下篇博客中继续介绍线程之间的同步和通信的方法。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值