• Java创建线程实例详解


    1.通过继承Thread类创建

    具体步骤为:
    1.继承Thread类,并重写run方法。run方法里面的逻辑就是线程要执行的逻辑。
    2.创建子类的对象实例。
    3.必须要使用对象实例的start方法启动该线程,不能直接使用run方法。

    public class MyThread extends Thread {
    
        @Override
        public void run() {
            for(int i=0; i<50; i++) {
                String threadName = Thread.currentThread().getName();
                System.out.println("cur thread is: " + threadName + ", i is: " + i);
            }
        }
    
        public static void main(String[] args) {
            MyThread thread1 = new MyThread();
            thread1.setName("线程1");
            MyThread thread2 = new MyThread();
            thread2.setName("线程2");
            thread1.start();
            thread2.start();
        }
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20

    某次运行的结果

    cur thread is: 线程1, i is: 0
    cur thread is: 线程1, i is: 1
    cur thread is: 线程1, i is: 2
    cur thread is: 线程1, i is: 3
    cur thread is: 线程1, i is: 4
    cur thread is: 线程1, i is: 5
    cur thread is: 线程1, i is: 6
    cur thread is: 线程1, i is: 7
    cur thread is: 线程1, i is: 8
    cur thread is: 线程1, i is: 9
    cur thread is: 线程1, i is: 10
    cur thread is: 线程1, i is: 11
    cur thread is: 线程1, i is: 12
    cur thread is: 线程1, i is: 13
    cur thread is: 线程1, i is: 14
    cur thread is: 线程1, i is: 15
    cur thread is: 线程1, i is: 16
    cur thread is: 线程1, i is: 17
    cur thread is: 线程1, i is: 18
    cur thread is: 线程1, i is: 19
    cur thread is: 线程1, i is: 20
    cur thread is: 线程1, i is: 21
    cur thread is: 线程1, i is: 22
    cur thread is: 线程1, i is: 23
    cur thread is: 线程1, i is: 24
    cur thread is: 线程1, i is: 25
    cur thread is: 线程1, i is: 26
    cur thread is: 线程1, i is: 27
    cur thread is: 线程1, i is: 28
    cur thread is: 线程1, i is: 29
    cur thread is: 线程2, i is: 0
    cur thread is: 线程1, i is: 30
    cur thread is: 线程2, i is: 1
    cur thread is: 线程1, i is: 31
    cur thread is: 线程2, i is: 2
    cur thread is: 线程1, i is: 32
    cur thread is: 线程2, i is: 3
    cur thread is: 线程1, i is: 33
    cur thread is: 线程2, i is: 4
    cur thread is: 线程1, i is: 34
    cur thread is: 线程2, i is: 5
    cur thread is: 线程1, i is: 35
    cur thread is: 线程2, i is: 6
    cur thread is: 线程1, i is: 36
    cur thread is: 线程2, i is: 7
    cur thread is: 线程1, i is: 37
    cur thread is: 线程2, i is: 8
    cur thread is: 线程1, i is: 38
    cur thread is: 线程2, i is: 9
    cur thread is: 线程1, i is: 39
    cur thread is: 线程2, i is: 10
    cur thread is: 线程1, i is: 40
    cur thread is: 线程2, i is: 11
    ....
    
    • 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
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54

    使用继承Thread的方式创建线程,缺点就是因为java的单继承机制,使得该类无法再继承其他类。

    2.通过Runnable接口创建

    具体步骤为:
    1.定义实现类实现Runnable接口,并实现run方法,run方法中的逻辑即为该线程的具体逻辑。
    2.创建Runnable实现类的实例,并以该实例作为Thread的target参数创建Thread对象。
    3.调用该Thread对象的start方法启动线程。

    public class MyRunnable implements Runnable {
    
        @Override
        public void run() {
            for(int i=0; i<50; i++) {
                String threadName = Thread.currentThread().getName();
                System.out.println("cur thread is: " + threadName + ", i is: " + i);
            }
        }
    
        public static void main(String[] args) {
            MyRunnable obj = new MyRunnable();
            new Thread(obj, "线程1").start();
            new Thread(obj, "线程2").start();
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16

    某次运行结果为:

    cur thread is: 线程2, i is: 0
    cur thread is: 线程1, i is: 0
    cur thread is: 线程2, i is: 1
    cur thread is: 线程1, i is: 1
    cur thread is: 线程2, i is: 2
    cur thread is: 线程1, i is: 2
    cur thread is: 线程2, i is: 3
    cur thread is: 线程1, i is: 3
    cur thread is: 线程2, i is: 4
    cur thread is: 线程1, i is: 4
    cur thread is: 线程2, i is: 5
    cur thread is: 线程1, i is: 5
    cur thread is: 线程2, i is: 6
    cur thread is: 线程2, i is: 7
    ...
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    3.Callable与Future创建

    基本步骤为:
    1.创建Callable接口实现类,实现run方法。注意Callable的源码为

    @FunctionalInterface
    public interface Callable {
        /**
         * Computes a result, or throws an exception if unable to do so.
         *
         * @return computed result
         * @throws Exception if unable to compute a result
         */
        V call() throws Exception;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    run方法中是后返回类型的。
    2.创建Callable实现类的实例对象,并使用Future的实现类FutureTask类包装Callable实例对象。
    3.使用FutureTask对象作为Thread对象的target创建并调用start方法启动线程。
    4.可以使用FutureTask对象的get方法获取子线程结束执行以后的返回值。

    import java.util.concurrent.Callable;
    import java.util.concurrent.ExecutionException;
    import java.util.concurrent.FutureTask;
    
    /**
     * author: wanglei
     * create: 2022-08-18
     */
    public class MyCallable implements Callable {
    
        @Override
        public Integer call() {
            for(int i=0; i<50; i++) {
                String name = Thread.currentThread().getName();
                System.out.println("子线程" + name + "值为" + i);
            }
            return 50;
        }
    
        public static void main(String[] args) {
            MyCallable obj = new MyCallable();
            FutureTask task = new FutureTask<>(obj);
            for(int j=0; j<50; j++) {
                System.out.println("主线程" + Thread.currentThread().getName() + "值为: " + j);
                if (j == 10) {
                    new Thread(task, "有返回值的线程").start();
                }
            }
            try {
                System.out.println("子线程返回值: " + task.get());
            } catch (InterruptedException e) {
                e.printStackTrace();
            } catch (ExecutionException e) {
                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
    • 35
    • 36
    • 37

    某次运行结果为

    /home/mi/wanglei/soft/jdk1.8.0_251/bin/java -agentlib:jdwp=transport=dt_socket,address=127.0.0.1:57127,suspend=y,server=n -javaagent:/home/mi/wanglei/soft/idea-IC-201.7223.91/plugins/java/lib/rt/debugger-agent.jar -Dfile.encoding=UTF-8 -classpath /home/mi/wanglei/soft/jdk1.8.0_251/jre/lib/charsets.jar:/home/mi/wanglei/soft/jdk1.8.0_251/jre/lib/deploy.jar:/home/mi/wanglei/soft/jdk1.8.0_251/jre/lib/ext/cldrdata.jar:/home/mi/wanglei/soft/jdk1.8.0_251/jre/lib/ext/dnsns.jar:/home/mi/wanglei/soft/jdk1.8.0_251/jre/lib/ext/jaccess.jar:/home/mi/wanglei/soft/jdk1.8.0_251/jre/lib/ext/jfxrt.jar:/home/mi/wanglei/soft/jdk1.8.0_251/jre/lib/ext/localedata.jar:/home/mi/wanglei/soft/jdk1.8.0_251/jre/lib/ext/nashorn.jar:/home/mi/wanglei/soft/jdk1.8.0_251/jre/lib/ext/sunec.jar:/home/mi/wanglei/soft/jdk1.8.0_251/jre/lib/ext/sunjce_provider.jar:/home/mi/wanglei/soft/jdk1.8.0_251/jre/lib/ext/sunpkcs11.jar:/home/mi/wanglei/soft/jdk1.8.0_251/jre/lib/ext/zipfs.jar:/home/mi/wanglei/soft/jdk1.8.0_251/jre/lib/javaws.jar:/home/mi/wanglei/soft/jdk1.8.0_251/jre/lib/jce.jar:/home/mi/wanglei/soft/jdk1.8.0_251/jre/lib/jfr.jar:/home/mi/wanglei/soft/jdk1.8.0_251/jre/lib/jfxswt.jar:/home/mi/wanglei/soft/jdk1.8.0_251/jre/lib/jsse.jar:/home/mi/wanglei/soft/jdk1.8.0_251/jre/lib/management-agent.jar:/home/mi/wanglei/soft/jdk1.8.0_251/jre/lib/plugin.jar:/home/mi/wanglei/soft/jdk1.8.0_251/jre/lib/resources.jar:/home/mi/wanglei/soft/jdk1.8.0_251/jre/lib/rt.jar:/home/mi/wanglei/gitcode/mycoding/target/classes:/home/mi/wanglei/soft/idea-IC-201.7223.91/lib/idea_rt.jar bit.edu.leilei.service.MyCallable
    Connected to the target VM, address: '127.0.0.1:57127', transport: 'socket'
    主线程main值为: 0
    主线程main值为: 1
    主线程main值为: 2
    主线程main值为: 3
    主线程main值为: 4
    主线程main值为: 5
    主线程main值为: 6
    主线程main值为: 7
    主线程main值为: 8
    主线程main值为: 9
    主线程main值为: 10
    主线程main值为: 11
    主线程main值为: 12
    主线程main值为: 13
    主线程main值为: 14
    主线程main值为: 15
    主线程main值为: 16
    主线程main值为: 17
    主线程main值为: 18
    主线程main值为: 19
    主线程main值为: 20
    主线程main值为: 21
    主线程main值为: 22
    主线程main值为: 23
    主线程main值为: 24
    主线程main值为: 25
    主线程main值为: 26
    主线程main值为: 27
    主线程main值为: 28
    主线程main值为: 29
    主线程main值为: 30
    子线程有返回值的线程值为0
    主线程main值为: 31
    子线程有返回值的线程值为1
    主线程main值为: 32
    子线程有返回值的线程值为2
    主线程main值为: 33
    子线程有返回值的线程值为3
    主线程main值为: 34
    子线程有返回值的线程值为4
    主线程main值为: 35
    子线程有返回值的线程值为5
    主线程main值为: 36
    主线程main值为: 37
    主线程main值为: 38
    主线程main值为: 39
    主线程main值为: 40
    主线程main值为: 41
    主线程main值为: 42
    主线程main值为: 43
    主线程main值为: 44
    主线程main值为: 45
    主线程main值为: 46
    主线程main值为: 47
    主线程main值为: 48
    主线程main值为: 49
    子线程有返回值的线程值为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
    子线程有返回值的线程值为35
    子线程有返回值的线程值为36
    子线程有返回值的线程值为37
    子线程有返回值的线程值为38
    子线程有返回值的线程值为39
    子线程有返回值的线程值为40
    子线程有返回值的线程值为41
    子线程有返回值的线程值为42
    子线程有返回值的线程值为43
    子线程有返回值的线程值为44
    子线程有返回值的线程值为45
    子线程有返回值的线程值为46
    子线程有返回值的线程值为47
    子线程有返回值的线程值为48
    子线程有返回值的线程值为49
    子线程返回值: 50
    Disconnected from the target VM, address: '127.0.0.1:57127', transport: 'socket'
    
    Process finished with exit code 0
    
    • 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
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106

    4.使用线程池创建

    实际工作场景中,使用线程池创建线程较为常见,具体可以参考如下。

    java线程池小结

    5.以上方式对比

    5.1 Thread方式

    直接继承Thread类的方式,实现简单方便,但是因为单继承问题,无法再继承其他类。

    5.2 Runnable方式

    解决了单继承问题,但是run方法返回的void类型,无法获取对应的返回值。同时,run方法也无法抛出异常。

    5.3 Callable方式

    1.Callable需要重写call方法,并且call方法可以返回值,同时还可以处理异常。
    2.Callable可以返回一个异步的Future对象。通过Future对象可以跟踪线程执行情况,并且可以通过get方法获取线程结果。

    5.4 线程池方式

    实际项目中,一般都是使用线程池进行线程管理。其优点有
    1.提升代码性能。因为创建线程是一个比较重的操作,使用线程池可以减少线程创建销毁等的性能开销。
    2.可以方便实现定时任务,控制并发数,单线程等功能。

  • 相关阅读:
    高等数学(第七版)同济大学 总习题三(后10题) 个人解答
    C++(适配器):stack和queue的底层实现,以及优先级队列和仿函数
    eventfd和__thread的应用
    【Freeradius】使用Freeradius、LDAP和Google Authenticator实现双因素身份验证
    dpdk 基于 rte_tailq_head 在多进程间共享内存的原理
    基于JAVA文件发布系统计算机毕业设计源码+系统+mysql数据库+lw文档+部署
    记一次 mac电脑 parallels desktop win10 虚拟机配置rsync文件同步功能(含mac 无法读写ntfs移动硬盘的解决方法)
    Linux: vi 编辑器
    QT mqtt 在子线程中使用
    常用的git指令
  • 原文地址:https://blog.csdn.net/bitcarmanlee/article/details/126409485