Java_the way to create threads

有句话说前头:

Java使用Thread类表示线程,所有线程都会是Thread类或者其子类的实例。

你所能想到的创建方式

先来说说最常用的实现多线程的两种方式:Thread和Runnable

  • Runnable是一个接口,包含一个run()方法
public interface Runnable{
	public abstract void run();
}

通过实现Runnable的方式来创建线程,实现多线程。比如:

class MyThread implements Runnable {
    private int i;

    //run方法:线程执行体
    public void run() {
        for (; i < 20; i++) {
            //当线程类实现Runnable接口时
            //如果想要获得当前线程,只能用Thread.currentThread()方法
            System.out.println(Thread.currentThread().getName()+ " " + i);
        }
    }

    public static void main(String[]args){
        //启动线程
        for(int i=0;i<20;i++) {
            System.out.println(Thread.currentThread().getName() + " " + i);
            if (i == 2) {
                MyThread mt = new MyThread();
                //通过new Thread(target,name)方法创建新线程
                new Thread(mt, "新线程1").start();
                new Thread(mt, "新线程2").start();
            }
        }
    }
}

运行结果:

main 0
main 1
main 2
main 3
main 4
main 5
main 6
main 7
main 8
main 9
main 10
main 11
main 12
main 13
main 14
main 15
main 16
main 17
main 18
main 19
新线程1 0
新线程1 1
新线程1 2
新线程1 3
新线程1 4
新线程1 5
新线程1 6
新线程2 6
新线程2 8
新线程2 9
新线程2 10
新线程2 11
新线程2 12
新线程2 13
新线程2 14
新线程2 15
新线程2 16
新线程2 17
新线程2 18
新线程1 7
新线程2 19

从Java8开始,Runnable接口使用了@FunctionalInterface修饰,也就是说,Runnable是函数式接口。

  • Thread是一个类,本身就实现了Runnable接口,声明如下:
public class Thread implements Runnable{}

实例如下:

class MyThread extends Thread {
    private int i;

    //run方法:线程执行体
    public void run() {
        for (; i < 20; i++) {
            //当线程类实现Runnable接口时
            //如果想要获得当前线程,只能用Thread.currentThread()方法
            System.out.println(Thread.currentThread().getName()+ " " + i);
        }
    }

    public static void main(String[]args){
        //启动线程
        for(int i=0;i<20;i++) {
            System.out.println(Thread.currentThread().getName() + " " + i);
            if (i == 2) {
                MyThread mt = new MyThread();
                //通过new Thread(target,name)方法创建新线程
                new Thread(mt, "新线程1").start();
                new Thread(mt, "新线程2").start();
            }
        }
    }
}

执行结果如下:

main 0
main 1
main 2
main 3
main 4
main 5
main 6
main 7
main 8
main 9
main 10
main 11
main 12
main 13
main 14
main 15
main 16
main 17
main 18
main 19
新线程1 0
新线程2 0
新线程2 1
新线程2 2
新线程2 4
新线程2 5
新线程2 6
新线程2 7
新线程2 8
新线程2 9
新线程2 10
新线程2 11
新线程2 12
新线程2 13
新线程2 14
新线程2 15
新线程2 16
新线程2 17
新线程2 18
新线程2 19
新线程1 20

通过上边的运行结果我们可以发现,线程1和线程2共享线程资源,一共创建了20个线程(共享MyThread)

  • 使用Callable和Future创建线程

从Java5之后提供了一种callable接口来创建线程,Callable接口提供了一个call()方法可以作为线程的执行体,和run()方法相比call()方法更为强大,如:

  1. 可以有返回值
  2. 可以声明抛出异常

因此可以提供一个Callable对象作为Thread的target,而该线程的线程执行体就是该对象的call方法,但是Callable不是Runnable的子接口,所以Callable对象不能直接作为Thread的target,而需要借助Future接口来代表Callable接口里call()方法的返回值,Future接口提供了一个FutureTask实现类,此类不仅实现了Future接口还实现了Runnable接口。
实例如下:

class MyThread {

    public static void main(String[] args) {
        //创建Callable对象
        MyThread mt = new MyThread();
        //先使用Lambda表达式创建Callable<Integer>对象
        //使用FutureTask包装callable对象
        FutureTask<Integer> task = new FutureTask<>((Callable<Integer>) () -> {
            int i = 0;
            for (; i < 20; i++) {
                //当线程类实现Runnable接口时
                //如果想要获得当前线程,只能用Thread.currentThread()方法
                System.out.println(Thread.currentThread().getName() + " " + i);
            }
            //call方法返回值
            return i;
        });
        //启动线程
        for (int i = 0; i < 20; i++) {
            System.out.println(Thread.currentThread().getName() + " " + i);
            if (i == 2) {
                //实质上还是使用callable对象创建并启动线程的
                new Thread(task, "有返回值的线程").start();
            }
        }
        try {
            //获取线程返回值
            System.out.println("子线程返回值: " + task.get());
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

执行结果:

main 0
main 1
main 2
main 3
main 4
main 5
main 6
main 7
main 8
main 9
main 10
main 11
main 12
main 13
main 14
main 15
main 16
main 17
main 18
main 19
有返回值的线程 0
有返回值的线程 1
有返回值的线程 2
有返回值的线程 3
有返回值的线程 4
有返回值的线程 5
有返回值的线程 6
有返回值的线程 7
有返回值的线程 8
有返回值的线程 9
有返回值的线程 10
有返回值的线程 11
有返回值的线程 12
有返回值的线程 13
有返回值的线程 14
有返回值的线程 15
有返回值的线程 16
有返回值的线程 17
有返回值的线程 18
有返回值的线程 19
子线程返回值: 20
孰优孰劣???

很难讲哪种方式就一定好,需要针对于具体的场景来说

采用实现Runnable、Callable接口的方式创建多线程:
    只是实现了Runnable接口或者Callable接口,还可以继承其他类
    多个线程可以共享一个target对象,非常适合多个相同的线程处理同一份资源的情况,从而将CPU、代码和数据分开,形成清晰的模型
    但是不足的就是编程复杂,如果要访问当前线程需要使用Thread.currentThread()方法

使用继承Thread类的方式创建多线程:
    编程简单,如果需要访问当前线程只需要用this指针就可以
    但是不足的就是因为继承了Thread类,就不能再继承其他父类了

简单总结一下:一般我们推荐的是使用实现Runnable接口或者Callable接口的方式来创建多线程

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

new_repo

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值