多线程的三种创建方式

创建方式1:继承Thread类

public class Demo_thread {
    /**
     * 多线程技术
     * 整个main方法是运行在main线程里的,也就是主线程
     * 后面再开启的线程,都是它的分支线程
     * @param args
     */
    public static void main(String[] args) {
        //Thread
        MyThread m = new MyThread();
        m.start();
        //与上面的是并发执行的
        for (int i=0; i<10 ; i++) {
            System.out.println("曲项向天歌"+i);
        }
    }
}
/**
 * 继承了Thread类的子类就是一个线程类
 */
public class MyThread extends Thread{

    /**
     * run方法就是线程要执行的任务方法
     * */
    @Override
    public void run() {
        //这里的代码就是一条新的执行路径
        //这个执行路径的触发方式,不是调用run方法
        //而是通过thread对象的start()方法,来启动任务。
        for (int i=0; i<10 ; i++) {
            System.out.println("鹅鹅鹅"+i);
        }

        //super.run();
    }
}

运行结果:
在这里插入图片描述
可以看出,两个线程的执行未必是均匀交替进行的,因为Java执行的是抢占性分配。两个线程并发执行,谁先执行完、谁快,是不确定的,每次执行的结果可能都不一样。

注意:每个线程都拥有自己的栈空间,共用一份堆内存。在执行过程中,每个线程任务里调用的方法,也都会相应地在该线程中运行。主要的处理方法是,方法入栈,然后弹栈。

简便方法:使用匿名内部类

public class Demo_thread2 {
    /**
     * 继承Thread方式的简便方法。
     */

    public static void main(String[] args) {
        new Thread(){
            @Override
            public void run() {
                for (int i = 0; i < 10; i++) {
                    System.out.println("哎呀"+i);
                }
            }
        }.start();

        for (int i = 0; i < 10; i++) {
            System.out.println("哎呀妈呀"+i);
        }
    }
}

运行结果:
在这里插入图片描述

创建方式2:实现Runnable接口

public class DemoRunnable {
    /**
     * 创建方式2:实现Runnable接口
     * @param args
     */
    public static void main(String[] args) {
        //实现Runnable
        //1.    创建一个任务对象
        MyRunnable r = new MyRunnable();
        //2.    创建一个线程,并为其分配一个任务
        Thread t = new Thread(r);
        //3.    执行这个线程
        t.start();
        for (int i=0;i<10;i++){
            System.out.println("曲项向天歌"+i);
        }
    }
}
/**
 * 用于给线程进行执行的任务
 */
public class MyRunnable implements Runnable{
    @Override
    public void run() {
        //线程的任务
        for(int i=0;i<10;i++){
            System.out.println("鹅鹅鹅"+i);
        }
    }
}

运行结果:
在这里插入图片描述

简便方法:使用匿名内部类

public class DemoAnonymousRunnable {
    public static void main(String[] args) {
        Thread t = new Thread(new Runnable() {
            @Override
            public void run() {
            	for(int i=0;i<10;i++){
            		System.out.println("鹅鹅鹅"+i);
        		}
            }
        });
        t.start();
        
        for (int i=0;i<10;i++){
            System.out.println("曲项向天歌"+i);
        }
    }
}

通过实现Runnable接口创建线程的优势

与继承Thread类相比,实现Runnable接口有如下优点:

  • 通过创建任务,然后给线程分配的方式来实现的多线程,更适合多个线程同时执行相同任务的情况。
  • 可以避免单继承所带来的局限性
    • (由于Java单继承、多实现的特性。通过继承Thread的方式创建线程,只能继承Thread类;而通过实现Runnable的方式创建线程,可以同时实现其他接口,并且能再去继承一个其他类)。
  • 任务与线程本身是分离的,提高了程序的健壮性。
  • 后续的线程池技术,只接受Runnable类型的任务(相对Thread类型而言),而不接收Thread类型的线程。

创建方式3:实现Callable接口

public class DemoCallable {

    public static void main(String[] args) throws ExecutionException, InterruptedException {
        Callable<Integer> c = new MyCallable();
        FutureTask<Integer> task = new FutureTask<>(c);
        new Thread(task).start();
        //调用get()方法,若不调用,主线程将不会等待子线程,主线程与子线程的结果将交替输出。
        //为了体现这一点,在主线程和子线程的输出中间打印一下get()方法的返回值。
        Integer j = task.get();
        System.out.println("返回值为:"+j);
        
        for (int i = 0; i < 10; i++) {
            try {
                Thread.sleep(100);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println(i);
        }
    }

    static class MyCallable implements Callable<Integer> {
        
        @Override
        public Integer call() throws Exception {
            for (int i = 0; i < 10; i++) {
                Thread.sleep(100);
                System.out.println(i);
            }
            return 100;
        }
    }

}

运行结果:
在这里插入图片描述

使用“实现Callable接口”的方式创建线程的特殊之处

继承Thread类 和 实现Runnable接口的方式都是不影响主线程的,与主线程并发执行。

而Callable不一样,它更像是主线程指派给它一个任务,它执行完毕后会有一个结果,主线程可以拿到这个结果。

Callable既可以实现与主线程并发执行,也可以让主线程等它执行完毕后给主线程返回一个结果。

Callable vs Runnable

相同点

  • 都是接口
  • 都可以编写多线程程序
  • 都采用Thread.start()启动线程

不同点

  • Runnable没有返回值;Callable可以返回执行结果
  • Callable接口的call()允许抛出异常;Runnable的run()不能抛出
已标记关键词 清除标记
©️2020 CSDN 皮肤主题: 数字20 设计师:CSDN官方博客 返回首页