Java多线程/并发01、新建线程的3种方法

来源:互联网 发布:怎样申请淘宝店 编辑:程序博客网 时间:2024/06/07 06:36

引子

首先要理解并发(Concurrency)并行(Parallelism)的区别:

  • 并发是在同一时段发生。多线程就是分时利用CPU,宏观上让所有线程一起执行,也叫并发。但在微观上不是同时执行的,只是把时间分成若干段,使多个进程快速交替的执行。这就好像两个人用同一把铁锨,轮流挖坑,一小时后,两个人各挖一个小一点的坑,要想挖两个大一点得坑,一定会用两个小时。
  • 并行是在同一时刻发生。无论从微观还是宏观,二者都是一起执行的,就好像两个人各拿一把铁锨在挖坑,一小时后,每人一个大坑。

从以上本质不难看出,“并发”执行,在多个进程存在资源冲突时,并没有从根本提高执行效率。

异步和多线程也不是一个同等关系,异步是最终目的,多线程只是我们实现异步的一种手段。异步是当一个调用请求发送给被调用者,而调用者不用等待其结果的返回而可以做其它的事情。实现异步可以采用多线程技术。

下面看看新建线程的3种方法 :

一、继承Thread,实现run()方法

只要两步即可创建并开启一个线程:
继承Thread类,并实现run()方法;
调用start()方法开启线程。

package twm.JConcurrence.demo;public class NewThreadDemo {    public static void main(String[] args) {        /*在主线程中开启10个线程,每个线程需要耗时2秒。但因为线程并发,所以总体运行时间也在2秒左右,并非20秒。*/        for (int i = 0; i < 10; i++) {            demothread abc= new demothread("chapter1_thread"+String.valueOf(i));            abc.start();        }    }    static class demothread extends Thread {        String put;        public demothread(String name) {            super(name);            this.put = name;        }        /*覆写run()方法*/        public void run() {            try {                /*模拟耗时操作,让线程休眠2秒*/                Thread.sleep(2000);            } catch (InterruptedException e) {                e.printStackTrace();            }            System.out            .println("Class name is : "+this.put+",thread name is :" + Thread.currentThread().getName());        }    }}

输出:

Class name is : chapter1_thread0,thread name is chapter1_thread0
Classname is : chapter1_thread2,thread name is chapter1_thread2
Class name is : chapter1_thread1,thread name is chapter1_thread1
Class name is : chapter1_thread4,thread name is chapter1_thread4
Class name is : chapter1_thread6,thread name is chapter1_thread6
Class name is : chapter1_thread8,thread name is chapter1_thread8
Class name is : chapter1_thread9,thread name is chapter1_thread9
Class name is : chapter1_thread3,thread name is chapter1_thread3
Class name is : chapter1_thread7,thread name is chapter1_thread7
Class name is : chapter1_thread5,thread name is chapter1_thread5

由于只要实现一个run()方法即可,所以可以改写一下上面程序,让代码更简洁。
使用Java中的匿名内部类(原型:new Thread(){ void run{ 实现 } }.start())来实现,代码如下:

package JConcurrence.Study;public class chapter1 {    public static void main(String[] args) {        for (int i = 0; i < 10; i++) {            final int m=i;            new Thread(){                /*覆写run()方法*/                public void run() {                    try {                        /*模拟耗时操作,让线程休眠2秒*/                        Thread.sleep(2000);                    } catch (InterruptedException e) {                        e.printStackTrace();                    }                    System.out                    .println("thread name is" + Thread.currentThread().getName()+"输出:"+m);                }            }.start();        }    }}

在for循环体内加了一句final int m=i;这是因为使用了匿名内部类,在类的内部隐式调用外部变量i,外部变量需要final修饰,不可修改值。否则会报错:Cannot refer to a non-final variable i inside an inner class defined in a different method

二 、实现Runnable接口

同样只要两步即可创建并开启一个线程:
创建一个实现了Runnable接口的类,并重写run()方法;
将该类的实例化对像作为参数传入Thread类的构造方法中,并调用Thread类的start()方法启动。

package JConcurrence.Study;public class chapter1 {    public static void main(String[] args) {        /*在主线程中开启10个线程,每个线程需要耗时2秒,但因为线程并发,所以总体运行时间也在2秒左右,并非20秒。*/        for (int i = 0; i < 10; i++) {            Runnable demoRunnable=new DemoRunable("chapter1runable"+String.valueOf(i));            new Thread(demoRunnable).start();        }    }    static class DemoRunable implements Runnable {        String put;        public DemoRunable(String name) {            super();            this.put = name;        }        /*覆写run()方法*/        public void run() {            try {                /*模拟耗时操作,让线程休眠2秒*/                Thread.sleep(2000);            } catch (InterruptedException e) {                e.printStackTrace();            }            System.out            .println("Class name is : "+this.put+",thread name is" + Thread.currentThread().getName());            }    }}

由于只要实现Runnable的一个run()方法,所以可以改写一下上面程序,让代码更简洁。
使用Java中的匿名内部类(原型:new Thread( new Runnable(){ void run{ 实现 } } ).start())来实现,代码如下:

package JConcurrence.Study;public class chapter1 {    public static void main(String[] args) {        /* 在主线程中开启10个线程,每个线程需要耗时2秒,但因为线程并发,所以总体运行时间也在2秒左右,并非20秒。 */        for (int i = 0; i < 10; i++) {            new Thread(new Runnable() {                @Override                public void run() {                    try {                        /* 模拟耗时操作,让线程休眠2秒 */                        Thread.sleep(2000);                    } catch (InterruptedException e) {                        e.printStackTrace();                    }                    System.out.println("thread name is"                            + Thread.currentThread().getName());                }            }).start();        }    }}

三、实现Callable接口

使用方法和Runable类似,但应用场景不同,会在后面的Callable和Future接口中详细说到Callable。

Runnable和Callable接口的区别:

  1. Callable重写的方法是call(),Runnable重写的方法是run();
  2. Callable的任务执行后可返回值,而Runnable不能返回值;
  3. call方法可以抛出异常,run()不可以;
  4. 运行Callable任务可以拿到一个future对象,表示异步计算的结果,
    它供检查计算是否完成的方法,以等待计算完成,并检索计算的结果。通过Future对象可以了解任务的执行情况,可取消任务的执行,还可以获取执行的结果。

四、总结Run()方法

无论继承Thread类还是实现Runnable接口,代码基本高度一致,核心就是在run()方法的实现中。
通过Thread源码中run()方法,可以看到它自己并不做什么(只是简单的判断一下是否可以调用),而是调用了target的run()方法

@Overridepublic void run() {    if (target != null) {        target.run();    }}

这个target到底是哪位大侠呢?跟踪发现是这样定义的:

private Runnable target;target就是Runnable。Runable的定义是:@FunctionalInterfacepublic interface Runnable {    public abstract void run();}

我了个去,满山遍野都是run,是不是感觉有零乱。
其实梳理一下就很好理解了。

1、如果我们要让Thread听我们指挥,做我们安排的工作,那么就直接重写Thread类run函数。甭管他里面什么target.run乱七八糟的,你自己想怎么写就怎么写,空着也行。这就是“1、继承Thread,实现run()方法”说讲的内容。

2、如果我们实现Runable接口,并重写他的run方法。而后将这个对像作为参数传入Thread,那么在Thread类内部,会把该参数赋值到target。线程启动后调用Thread.run时运行的代码是target.run(),最终调用了runable实现类中的run方法。所以可以你在runable中的run方法中自己想怎么写就怎么写,空着也行。这就是“实现Runnable接口”讲的内容

3、如果有个哥们他硬要把两样都加上,即:同时把将runable传入Thread,然后又实现Thread中的run方法,那么程序最终会运行runable中的run(),还是Thread中的run()呢?….舌头差点打结了。很明显因为重写Thread中的run方法后,就不会再执行target.run了。因此无论你传什么runable进来,Thread都不会理睬了。看代码:

package JConcurrence.Study;public class chapter1 {    public static void main(String[] args) {        new Thread(new Runnable() {            @Override            public void run() {                try {                    /* 模拟耗时操作,让线程休眠2秒 */                    Thread.sleep(2000);                } catch (InterruptedException e) {                    e.printStackTrace();                }                System.out.println("Executive agent:Runable 's run()");            }        }) {            public void run() {                try {                    /* 模拟耗时操作,让线程休眠2秒 */                    Thread.sleep(2000);                } catch (InterruptedException e) {                    e.printStackTrace();                }                System.out                        .println("Executive agent:Thread 's Override run()");            }        }.start();    }}

执行结果:

Executive agent:Thread ‘s Override run()

0 0
原创粉丝点击