04. 异步线程创建-Runnable 方式

java 多线程系列文章列表, 请查看目录: 《java 多线程学习笔记》

1. 实现Runnable接口

实现Runnable接口方式, 是一种非常常用的方式. 适用于无须监控异步线程结束时间, 无须捕获异步线程返回值情景
直接继承Thread类是创建异步线程最简单的方式, 但并不常用. 匿名内部类的方式可以考虑.

1.1 Runnable 方式特点

  • 面向接口编程, 松耦合设计
  • 在多线程模式下,可实现对象资源共享. 但是需要注意使用原子类变量AtomicXXX
  • 不能独立运行, 需绑定在Thread实例上运行
  • 主线程不能监控子线程何时结束, 也不能获取子线程返回结果
  • 切记启动异步线程的方式是调用star()方法, 而非调用run()方法.
  • 主线程不能捕获子线程的抛出的异常, 通常会在run()方法中包裹一个最大的try-catch,自行处理异常

1.2 使用步骤

  • 创建Runnable 子类, 实现run()方法. 可采用内部类, Lambda表达式,匿名内部类等方式.
  • 创建Thread实例,绑定Callable实例
  • 通过Thread实例的start()方法启动线程

1.3 适用场景

主线程无须监控异步线程何时结束, 也无须获取子线程执行结果

2. 异步线程示例

2.1 异步线程

public static void main(String[] args) {

    // 创建runnable 实例
    Runnable runnable = new Runnable() {
        @Override
        public void run() {
            System.out.println("执行线程名称:" + Thread.currentThread().getName());
        }
    };

    // 启动子线程
    new Thread(runnable).start();

    // 主线程输出
    System.out.println("执行线程名:" + Thread.currentThread().getName());
}

2.2 输出

执行线程名称:Thread-0
执行线程名:main

3. 多线程示例

3.1 多线程示例

  • 通过for循环创建多个线程只是为了测试, 企业开发中通常会使用线程池.
  • 共享变量times需要使用原子类型变量, 否则会有并发问题
  • 需要注意while判断条件的写法, 将获取, 自增, 判断作为一个原子操作进行, 否则也会有原子操作问题.
  • 通常会将run方法整个方法体至于一个try-catch中, 当以后异常发生时自行捕获处理, 因为主线程不能捕获子线程中的异常.
public static void main(String[] args) {

    try {
        // 创建runnable 实例
        Runnable runnable = new Runnable() {

            // 记录总次数
            private AtomicInteger times = new AtomicInteger(0);

            @Override
            public void run() {
                // 当前线程执行第几次
                int idx = 0;
                while ((idx = times.getAndIncrement()) < 10) {
                    try {
                        Thread.sleep(200l);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    System.out.println(Thread.currentThread().getName() + " 执行第[" + idx + "]次操作");
                }
            }
        };
        // 启动子线程
        for (int i = 0; i < 3; i++) {
            new Thread(runnable).start();
        }

        // 主线程输出
        System.out.println("执行线程名:" + Thread.currentThread().getName());
    } catch (Exception e) {
        e.printStackTrace();
    }

}

3.2 输出

测试输出可以看出, 由3个线程共同执行了10次操作.

执行线程名:main
Thread-0 执行第[0]次操作
Thread-1 执行第[1]次操作
Thread-2 执行第[2]次操作
Thread-0 执行第[3]次操作
Thread-1 执行第[4]次操作
Thread-2 执行第[5]次操作
Thread-0 执行第[6]次操作
Thread-1 执行第[7]次操作
Thread-2 执行第[8]次操作
Thread-0 执行第[9]次操作

你可能感兴趣的:(juc)