Thread与Runnable的选择

前言

Thread类创建对象的方式主要有两种,一个是Thread()构造,一个是Thread(Runnable target)构造。
先来看一下Thread类和Runnable接口的关系,Thread类实现了Runnable接口,并且Runnable是一个函数式接口,无入参,无返回值,这就说明可以直接写lambda进行灵活的实现了。
在这里插入图片描述
在这里插入图片描述

创建线程的两种方式

Thread()构造

使用Thread()构造来创建线程的话,直接在自定义的Thread类里面重写一个run方法就可以了。

public class RunnableThread {

    public static void main(String[] args) {
    	//创建一个新的线程
        Thread myThread = new MyThread();
        //线程执行用start方法
        myThread.start();
        System.out.println("this is mainThread");
    }
}

class MyThread extends Thread {
    @Override
    public void run() {
        System.out.println("this is myThread");
    }
}

或者写个匿名内部类

public class RunnableThread {

    public static void main(String[] args) {

        //创建一个新的线程
        Thread myThread = new Thread() {
            @Override
            public void run() {
                System.out.println("this is myThread");
            }
        };
        //线程执行用start方法
        myThread.start();
        System.out.println("this is mainThread");

    }
}

这里有一个小的要点,我们在主线程(main方法里)来调用子线程的方法时,一般采用start()方法,而不采用run方法,如果使用run方法的话,它就是一个普通的方法而已,不是异步的,就会变成在哪个线程里执行run方法,就会让哪个线程来执行。
如下采用run方法的执行结果:
在这里插入图片描述
采用start方法才能起到异步的作用:
在这里插入图片描述

Thread(Runnable target)构造

该构造里面放了一个Runnable接口,这就意味着也可以通过lambda表达式结合策略模式来创建新的线程了。
方案一:

public class RunnableThread {

    public static void main(String[] args) {
        Thread myThread = new Thread(new MyRunnable());
        System.out.printf("this is mainThread %s%n",Thread.currentThread().getName());
        myThread.start();
    }
}

class MyRunnable implements Runnable{
    @Override
    public void run() {
        System.out.printf("this is myThread %s%n",Thread.currentThread().getName());
    }
}

方案二:

public class RunnableThread {

    public static void main(String[] args) {

        Runnable runnable = new Runnable() {
            @Override
            public void run() {
                System.out.printf("this is myThread %s%n", Thread.currentThread().getName());
            }
        };

        Thread myThread = new Thread(runnable);
        System.out.printf("this is mainThread %s%n",Thread.currentThread().getName());
        myThread.start();
    }
}
}

或者直接利用lambda:

public class RunnableThread {

    public static void main(String[] args) {
        System.out.println("this is mainThread");
        new Thread(()->{
            System.out.println("this is myThread");
        }).start();
    }
}

二者的区别

源码分析

在这里插入图片描述
他们的区别也很明显,就在于有没有这个Runnable的参数
在这里插入图片描述

如果创建线程的时候有Runnable的参数的话,才会执行Runnable的run方法,也就是通过Thread(Runnable target)方法创建的时候;否则什么也不做,也就执行Thread子类的run方法了。

二者的选择

从面向对象的角度来看,通过Thread子类来创建的方式为泛化的关系,通过Runnable接口作为入参的方式为依赖的关系,所以后者的耦合性相对于前者来说要低一些,这样来看,后者是优先采用的方式。

从线程的安全性角度来分析,一个Runnable实例可以被多个线程来使用,有可能使用的结果会超出我们的预期,比如下面这个例子,由于多个线程共享一个Runnable变量,最后的结果会是500,进行了累加

  public static void main(String[] args) {
        Thread thread;
        Runnable runnable = new Runnable() {
            private int count;
            @Override
            public void run() {
                for (int i = 0; i < 100; i++) {
                    count++;
                }
                System.out.printf("ThreadName:%s-----%d      ", Thread.currentThread().getName(), count);
            }
        };
        for (int i = 0; i < 5; i++) {
            thread = new Thread(runnable);
            thread.start();
        }

    }

在这里插入图片描述
而通过Thread()的方式,每个线程的结果都是100,是线程隔离的

 public static void main(String[] args) {
        Thread thread;
        for (int i = 0; i < 5; i++) {
            thread = new Thread() {
                private int count;

                @Override
                public void run() {
                    for (int i = 0; i < 100; i++) {
                        count++;
                    }
                    System.out.printf("ThreadName:%s-----%d      ", Thread.currentThread().getName(), count);
                }
            };
            thread.start();
        }
    }

执行结果为每个线程都是100
在这里插入图片描述
希望各位大佬多多指点,共同进步~

  • 3
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值