线程的基本使用

Posted XeonYu

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了线程的基本使用相关的知识,希望对你有一定的参考价值。

上一篇 多线程的基本概念

了解完多线程的概念之后,我们先来看一下线程的基本使用。

Java线程的两种实现方式

Java中实现线程的方式有两种

  1. 继承自Thread类,在子类实现run方法
  2. 实现Runnable接口,重写run方法

我们先来简单看看Thread类

Thread类实现了Runnable接口

Runnable接口中只有一个run方法,实际上,线程的任务就是在run方法中执行的,也就是说我们实际开发过程中就是在run方法里写业务代码。

方式一:继承Thread类

public class MyWorkThread extends Thread {
    @Override
    public void run() {

        for (int i = 0; i < 100; i++) {
            System.out.println(Thread.currentThread().getName() + "执行任务。。。" + i);
        }
    }
}
public class TestJava {

    public static void main(String[] args) {

        /*创建子线程*/
        MyWorkThread myWorkThread = new MyWorkThread();
        /*启动myWorkThread*/
        myWorkThread.start();
        
        /*主线程打印*/
        for (int i = 0; i < 100; i++) {
            System.out.println(Thread.currentThread().getName() + "执行任务。。。" + i);
        }
    }
}

运行结果如下:

一般我们不会使用这种方式去实现多线程,因为这种写法比较死板,定义好的线程只能实现固定的写好的任务。


方式二:实现Runable接口

package methord2;

public class MyRunnable implements Runnable {
    @Override
    public void run() {

        for (int i = 0; i < 100; i++) {
            System.out.println("MyRunnable" + i);

        }
    }
}
package methord2;

public class Test {
    public static void main(String[] args) {

        MyRunnable myRunnable = new MyRunnable();

        Thread thread = new Thread(myRunnable);
        thread.start();

        for (int i = 0; i < 100; i++) {
            System.out.println("main :" + i);
        }
    }
}

运行结果:

通过匿名内部类简化代码:

可以看到 Thread 构造接收的Runnable是个接口,那我们可以使用匿名内部类来简化一下代码,如下:

        Thread thread = new Thread(new Runnable() {
            @Override
            public void run() {
                for (int i = 0; i < 100; i++) {
                    System.out.println("Runnable" + i);
                }
            }
        });

        thread.start();

通过Lambda表达式简化代码

由于Runnable接口中只有一个方法,那我们还可以直接写成Lambda的方式,代码如下

        Thread thread = new Thread(() -> {
            for (int i = 0; i < 100; i++) {
                System.out.println("Runnable" + i);
            }
        });

        thread.start();

这样一来,相比方式一,代码就简洁很多了,而且更加灵活。

Kotlin的写法就更简单了,如下:

fun main() {

    /*创建线程并启动*/
    Thread {
        for (i in 1..100) {
            println("${Thread.currentThread().name}=========>${i}")
        }

    }.start()


    /*主线程*/
    for (i in 1..100) {
        println("${Thread.currentThread().name}=========>${i}")
    }

}

运行结果:

Runnable接口中的run方法是没有返回值的,如果我们想获取线程执行的返回结果,可以使用Callable

先看下Callable接口,可以看到,Callable接口接收一个泛型,实际执行的方法是call方法,且这个方法是有返回值的。

这里总结一下Callable和Runnable的区别:

Runnable:实际执行的是 run 方法,没有返回值

Callable: 实际执行的是 call 方法,有返回值

下面我们来看下怎么用:

新建一个类,实现Callable接口,可以指定返回值的类型,并实现call方法。

class MyCallable implements Callable<String> {

    @Override
    public String call() throws Exception {

        Thread.sleep(1000);
        return "success";
    }
}

看Thread源码可以看到,Thread构造接收的是Runnable类型的参数

所以,我们不能直接将Callable的实现类直接传进去 , 需要用到 FutureTask  包装一下

先来看下 FutureTask 的代码,可以看到 FutureTask 类实现了RunnableFuture接口

RunnableFuture 又继承了 Runnable 接口,所以,本质上还是属于实现Runnable接口的方式 

这样一来,我们就可以将FutureTask 类型的对象传给Thread了。

用法如下:

    public static void main(String[] args) {

        /*创建 Callable 对象*/
        MyCallable callable = new MyCallable();
        /*包装成FutureTask*/
        FutureTask<String> stringFutureTask = new FutureTask<>(callable);
        /*创建线程并开始执行*/
        new Thread(stringFutureTask).start();

        System.out.println("线程开始执行");
        try {
            /*拿返回结果*/
            String result = stringFutureTask.get();
            System.out.println("执行完毕 拿到结果");
            System.out.println("result = " + result);
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
        }

        System.out.println("主线程执行");


    }

下面来看下运行结果:

可以看到,我们可以拿到执行结果了。需要注意的是,这里调FutureTask的get会阻塞当前线程

java 简化写法:

    public static void main(String[] args) {

        /*创建FutureTask 对象*/
        FutureTask<String> stringFutureTask = new FutureTask<>(() -> {
            Thread.sleep(1000);
            return "success";
        });

        /*创建线程并开始执行*/
        new Thread(stringFutureTask).start();

        System.out.println("线程开始执行");
        try {
            /*拿返回结果*/
            String result = stringFutureTask.get();
            System.out.println("执行完毕 拿到结果");
            System.out.println("result = " + result);
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
        }
        System.out.println("主线程执行");
    }

kotlin写法就更简单了,如下:

fun main() {


    /*创建FutureTask对象*/
    val futureTask = FutureTask {
        Thread.sleep(1000)
        "Success"
    }

    /*创建线程执行任务*/
    Thread(futureTask).start()
    /*打印*/
    println("futureTask = ${futureTask.get()}")
}

好了,本篇文章就是这样

下一篇:

线程的状态


如果你觉得本文对你有帮助,麻烦动动手指顶一下,可以帮助到更多的开发者,如果文中有什么错误的地方,还望指正,转载请注明转自喻志强的博客,谢谢!

以上是关于线程的基本使用的主要内容,如果未能解决你的问题,请参考以下文章

为啥基于锁的程序不能组成正确的线程安全片段?

html PHP代码片段: - AJAX基本示例:此代码演示了使用PHP和JavaScript实现的基本AJAX功能。

活动到片段方法调用带有进度条的线程

JUC并发编程 共享模式之工具 JUC CountdownLatch(倒计时锁) -- CountdownLatch应用(等待多个线程准备完毕( 可以覆盖上次的打印内)等待多个远程调用结束)(代码片段

多线程 Thread 线程同步 synchronized

c_cpp Robolution基本代码片段