• java并发编程-实现线程的方法


    实现方法

    一、继承Thread类

    Thread类实现
    Thread类本质是实现了Runnable接口的一个实例,代表一个线程的实例。
    启动线程
    通过Thread类的start()实例方法。
    start()方法是一个native方法,它将启动一个新的线程,并执行run()方法,就可以启动新线程并执行自己定义的run()方法

    优缺点
    优点:代码简单
    缺点:该类无法继承别的类

    代码实现

    public class NewThread extends Thread {
    
        private String name;
        public NewThread(String name){
            this.name = name;
        }
        public void run(){
            for(int i = 0; i < 5; i++){
                System.out.println(name+"运行:"+i);
    
                try {
                    sleep((long) (Math.random()*10));
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    public static void main(String[] args) {
    
            NewThread mTh1 = new NewThread("a");
            NewThread mTh2 = new NewThread("b");
    
            mTh1.start();
            mTh2.start();
    
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    ab线程交替运行

    二、实现Runnable接口

    public class NewRunnable implements Runnable {
    
        private String title;
        public NewRunnable(String title) {
            this.title = title;
        }
        @Override
        public void run() { // 线程的主方法
            for (int x = 0; x < 10; x++) {
                System.out.println(this.title + "运行,x = " + x);
            }
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
     public static void main(String[] args) {
     
            NewRunnable myThread1 = new NewRunnable("A");
            NewRunnable myThread2 = new NewRunnable("B");
    
            new Thread(myThread1).start();
            new Thread(myThread2).start();
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    要启动多线程依靠Thread类的start()方法完成
    实现的是Runnable接口,没有这个方法可以继承
    需要依靠Thread类中的 一个构造方法:public Thread(Runnable target),来接收Runnable接口对象

    优缺点

    优点:继承其他类,统一实现该接口的实例可以共享资源
    缺点:代码复杂

    三、实现Callable接口

    public class NewCallable implements Callable<Integer> {
    
        private String name;
        public NewCallable(String name){
            this.name = name;
        }
    
        @Override
        public Integer call() throws Exception {
    
            int sum = 0 ;
            for (int i = 0; i <= 100; i++){
                System.out.println(name +"线程:"+i);
                sum +=i;
            }
            return sum;
        }
    
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    import java.util.concurrent.ExecutionException;
    import java.util.concurrent.FutureTask;
    
    public class MainTest {
    
        public static void main(String[] args) {
    
            NewCallable th1 = new NewCallable("A");
            NewCallable th2 = new NewCallable("B");
    
            //1.执行callable方式,需要futureTask实现类的支持,用于接受运算结果
            FutureTask<Integer> result1 = new FutureTask<>(th1);
            FutureTask<Integer> result2 = new FutureTask<>(th2);
    
            new Thread(result1).start();
            new Thread(result2).start();
    
            Integer sum;
            try {
                sum = result1.get();
                System.out.println("-----------");
                System.out.println(sum);
                
                sum = result2.get();
                System.out.println("-----------");
                System.out.println(sum);
    
            } catch (InterruptedException | ExecutionException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();         
            }
        }
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34

    Future 和 FutureTask

    四、线程池的方式

    线程池,其实就是一个容纳多个线程的容器,其中的线程可以重复使用,省去了频繁创建对象的操作,因为反复创建线程是非常消耗资源的

    线程池是线程工厂创建线程的,默认采用 DefaultThreadFactory ,它会给线程池创建的线程设置一些默认值,比如:线程的名字、是否是守护线程,以及线程的优先级等。
    本质通过 new Thread() 创建线程的 ,只不过这里的构造函数传入的参数要多一些,由此可以看出通过线程池创建线程并没有脱离最开始的那两种基本的创建方式,还是通过 new Thread() 实现的。

    优点:实现自动化装配,易于管理,循环利用资源

    五、其他创建方式

    定时器Timer

    class TimerThread extends Thread {
        // TODO 
    }
    
    • 1
    • 2
    • 3

    定时器也可以实现线程,如果新建一个 Timer,令其每隔 10 秒或设置两个小时之后,执行一些任务,那么这时它确实也创建了线程并执行了任务。
    本质上有一个继承自 Thread 类的 TimerThread,所以定时器创建线程最后又绕回到最开始说的两种方式。

    匿名内部类创建线程

    
    new Thread(new Runnable() {
                @Override
                public void run() {
                    System.out.println(Thread.currentThread().getName());
                }
            }).start();
    
    
    new Thread(() -> System.out.println(Thread.currentThread().getName())).start();
    
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    匿名内部类或 lambda 表达式创建线程仅仅是在语法层面上实现了线程,匿名内部类实现线程仅仅是用一个匿名内部类把需要传入的 Runnable 给实例出来。

    线程的实现

    1.实现

    1.启动线程需要调用 start() 方法,而start() 方法调用 run() 方法,源码中 target 实际上就是一个 Runnable,即使用 Runnable 接口实现线程时传给Thread类的对象。

    
    private Runnable target;
    
    //Thread中的run方法
        @Override
        public void run() {
            if (target != null) {
                target.run();
            }
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    1. 继承 Thread 方式,实际上,继承 Thread 类之后,会把上述的 run() 方法重写,重写后 run() 方法里直接就是所需要执行的任务,但它最终还是需要调用 thread.start() 方法来启动线程,而 start() 方法最终也会调用这个已经被重写的 run() 方法来执行它的任务,事实上创建线程只有一种方式,就是构造一个 Thread 类。

    2.运行内容

    运行内容主要来自于两个地方,要么来自于 target,要么来自于重写的 run() 方法,

    实现线程只有一种方式,而要想实现线程执行的内容,却有两种方式,① 可以通过 实现 Runnable 接口的方式,②继承 Thread 类重写 run() 方法的方式,把想要执行的代码传入,让线程去执行。

    3.比较

    为什么说实现 Runnable 接口比继承 Thread 类实现线程要好

    代码的架构
    Runnable 里只有一个 run() 方法,它定义了需要执行的内容,在这种情况下,实现了 Runnable 与 Thread 类的解耦,Thread 类负责线程启动和属性设置等内容,权责分明。

    某些情况下可以提高性能
    继承 Thread 类方式,每执行一次任务,都需要新建一个独立的线程,执行完任务后线程走到生命周期的尽头被销毁,如果此时执行的内容比较少(只是在 run() 方法里简单打印一行文字),那么它所带来的开销并不大,相比于整个线程从开始创建到执行完毕被销毁,这一系列的操作比 run() 方法打印文字本身带来的开销要大得多。
    如果我们使用实现 Runnable 接口的方式,就可以把任务直接传入线程池,使用一些固定的线程来完成任务,不需要每次新建销毁线程,大大降低了性能开销。

    Java 语言不支持双继承
    如果类一旦继承了 Thread 类,那么它后续就没有办法再继承其他的类,限制了代码未来的可拓展性。

    Callable 和 Runnable 的不同

    Runnable

    • 不能返回一个返回值
    • 不能抛出 checked Exception

    源码:

    public interface Runnable {
        //返回值为void且没有声明抛出任何异常
        public abstract void run();
    }
    
    • 1
    • 2
    • 3
    • 4

    Callable

    public interface Callable<V> {
        /**
         * Computes a result, or throws an exception if unable to do so.
         *
         * @return computed result
         * @throws Exception if unable to compute a result
         */
         //声明了 throws Exception 和 V 泛型的返回值,
        V call() throws Exception;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    不同点

    • 方法名: Callable 规定的执行方法是 call(),而 Runnable 规定的执行方法是 run();
    • 返回值: Callable 的任务执行后有返回值,而 Runnable 的任务执行后是没有返回值的;
    • 抛出异常 call() 方法可抛出异常,而 run() 方法是不能抛出受检查异常的;
    • Future 类: 和 Callable 配合的有一个 Future 类,通过 Future 可以了解任务执行情况,或者取消任务的执行,还可获取任务执行的结果,这些功能都是 Runnable 做不到的,Callable 的功能要比 Runnable 强大。
  • 相关阅读:
    互联网产品经理的月薪是多少?治好奇!
    uni-app 页面跳转动画
    建一个chrome插件crx所需步骤
    GET 和 POST 请求类型的区别
    企业架构LNMP学习笔记36
    写一个flutter程序2
    14. Mybatis 删除操作-delete
    spring 事件监听器的使用及事件异步处理
    数据库:Hive转Presto(一)
    Python的垃圾回收机制
  • 原文地址:https://blog.csdn.net/weixin_39795049/article/details/127830628