多线程之(线程创建)

2020-06-28  本文已影响0人  新征程Dream

[Toc]

线程创建

作为一名优秀的程序员,怎么能不懂多线程呢?那想搞懂多线程,第一步就是先创建线程跑起来。说到创建线程,方式多种多样。其实最根本的就是三种方式,剩下的无非就是语法变一变的玩意。

创建线程的三种方式

第一种,继承Thread.

先说为什么要继承Thread类呢?为什么不直接new 一个Thread对象来创建线程呢?原则上是可以直接new 一个Thread对象来创建一个线程。但是我们要想一下创建一个线程做什么呢?对的,肯定是想来跑我们自己的代码。我们应该知道当线程被开启执行的是run()方法。即使不知道,那就记住。这个run()方法就存在于Thread中。但是呢Thread中的run()方法几乎是没什么东西的,那我们肯定要把自己的代码写到run()方法中,那怎么来写呢?继承父类就可以重写。这样讲,就明白为什么要继承Thread类了吧。
话不多说上码

package cn.zl;
// 第一种方式创建线程,通过继承Thread。
public class ThreadTest extends Thread{
    private int count = 10000;
    @Override
    public void run() {
        while (true){
            System.out.println("count"+count);
            if (--count<0){
                break;
            }
        }
    }
}

既然我们的线程已经创建好,那就跑一把。

package cn.zl;
public class Main {
    public static void main(String[] args) {
      // 创建线程
        ThreadTest threadTest = new ThreadTest();
      //  启动线程
        threadTest.start();
      // 为了我们执行的结果可以交叉显示,所以写了以下代码。
        int i=10000;
        while (i>0){
            System.out.println("Main"+i);
            i--;
        }
    }
}

这时候,有个重点,就是我们线程启动,是通过start()方法,而不是直接调用run()方法。想要搞定这个东西,都需要研究一下JVM。因为start()方法其实是一个本地方法,由C/C++来实现的。但是对于我们Java程序员来讲,我们要记住线程启动时通过调用start()方法。第一种方式已经完成,学习是一个循序渐进的过程,尤其对java程序员来说,先学会怎么用,再去研究原理。

第二种,实现Runnable接口.

还是刚才那个问题,有没有不通过继承Thread的方式来重写run()方法呢?答案肯定是有的。Thread这个类对外提供了传参Runnable的实现类来重写run()方式。于是这就是我们要说的第二种了。通过实现Runnable接口中的run()方法,并把此实现类当做参数传入Thread中。
话不多说,上码

package cn.zl;
// 第二种线程创建的方式,实现Runnable
public class RunnableTest implements Runnable {
    private int i = 10000;
    public void run() {
        while (i > 0) {
            System.out.println("Runnable" + i);
            i--;
        }
    }
}

跑一把

package cn.zl;
public class Main {
    public static void main(String[] args) {
        // 创建一个线程
        Thread thread = new Thread(new RunnableTest());
        // 启动线程
        thread.start();
       // 为了我们执行的结果可以交叉显示,所以写了以下代码。
        int i=10000;
        while (i>0){
            System.out.println("Main"+i);
            i--;
        }
    }
}

这样第二种方式就完成了。稍后讲一下三种的区别。既然存在三种,三种一定有所不同。

第三种,实现Callable接口

这一种,猛一下类似于第二种。这一种,我们不是通过实现run()方法来重写Thread中的run()方法,而是我们通过实现call()方法来重写Thread中的run()方法。
废话不多说,上码

package cn.zl;
import java.util.concurrent.Callable;
// 第三种创建线程的方式,实现Callable方式
public class CallableTest implements Callable<Integer> {
    private int i = 10000;
    public Integer call() throws Exception {
        while (i>0){
            System.out.println("Callable"+i);
            i--;
        }
        return i;
    }
}

跑一下

package cn.zl;

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

public class Main {
    public static void main(String[] args) {
         // 创建Future对象来装载Callable的实现类对象(CallableTest)。
        FutureTask<Integer> integerFutureTask = new FutureTask<Integer>(new CallableTest());
        // 创建线程
        Thread thread1 = new Thread(integerFutureTask);
       // 启动线程
        thread1.start();
        try {
          //  获取线程中的返回值,并输出
            System.out.println(integerFutureTask.get()+"--------------");
        } catch (InterruptedException e) {
            e.printStackTrace();
        } catch (ExecutionException e) {
            e.printStackTrace();
        }
        // 为了我们执行的结果可以交叉显示,所以写了以下代码。
        int i=10000;
        while (i>0){
            System.out.println("Main"+i);
            i--;
        }
    }
}

通过以上的代码,我们可以感受到。用实现Callable方式,我们不仅能创建线程,还能获取线程的返回值。而不是像之前一样,线程启动了,到结束都不给我们打个招呼。这种方式,就比较友好。不受控,对程序员来说是一件很可怕的事情。

三种方式的优缺点

start()和run() 的区别

消化一下,后续写更深点的东西,学习讲究循序渐进。

上一篇 下一篇

猜你喜欢

热点阅读