Thread与Runnable的选择

  • A+
所属分类:多线程

前言

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

创建线程的两种方式

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方法的执行结果:
Thread与Runnable的选择
采用start方法才能起到异步的作用:
Thread与Runnable的选择

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();
    }
}

二者的区别

源码分析

Thread与Runnable的选择
他们的区别也很明显,就在于有没有这个Runnable的参数
Thread与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与Runnable的选择
而通过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
Thread与Runnable的选择
希望各位大佬多多指点,共同进步~

w3cjava

发表评论

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen: