美文网首页
JUC 之线程创建

JUC 之线程创建

作者: Tinyspot | 来源:发表于2023-11-12 10:14 被阅读0次

    1. 线程类Thread

    在 JDK 中代表线程的就只有 Thread 类
    准确地讲,创建线程只有一种方式那就是构造 Thread 类,而实现线程的执行单元则有两种方式,第一种是重写 Thread 的 run(), 第二种是实现 Runnable 接口的 run(), 并且将 Runnable 实例用作构造 Thread 的参数

    1.1 java.lang.Thread

    public class Thread implements Runnable {
        // 线程名字
        private volatile String name;
        private int            priority;
        // 线程的唯一标识符
        private long tid;
    
        private Runnable target;
        private ThreadGroup group;
    
        // 线程的执行单元 run()
        @Override
        public void run() {
            if (target != null) {
                target.run();
            }
        }
    }
    

    1.2 创建线程的两种方式

    • 方式一:继承 Thread 类
    • 方式二:实现Runnable接口

    2. 继承 Thread 类

    @Slf4j
    public class MyThread extends Thread {
        /**
         * this.getId() 和 this.getName() 有局限性,必须 extends Thread 才能使用,因为这是父类中的方法
         */
        @Override
        public void run() {
            log.info("线程id: " + this.getId() + "; 线程名称: " + this.getName());
            log.info("Thread name: " + Thread.currentThread().getName());
        }
    }
    

    调用

    @Test
    public void run() {
        MyThread thread = new MyThread();
        thread.start();
    }
    

    打印结果:

    18:29:28.230 [Thread-1] INFO juc.MyThread - 线程id: 14; 线程名称: Thread-1
    18:29:28.235 [Thread-1] INFO juc.MyThread - Thread name: Thread-1
    

    2.2 匿名内部类方式

    • 语法 new 父类() { 子类 };
    • 匿名类是一个表达式,因此在定义的最后用分号结束

    例如:通过匿名类方式创建线程

    @Test
    public void run() {
        Thread thread = new Thread() {
            // 子类重写父类的run()
            @Override
            public void run() {
                log.info("run...");
            }
        };
        thread.start();
    }
    

    打印结果:

    18:39:39.258 [Thread-1] INFO juc.JUCDemo - run...
    

    也可写成如下:

    @Test
    public void run() {
        new Thread() {
            @Override
            public void run(){
                log.info("run...");
            }
        }.start();
    }
    

    2.3 其他方式:将线程对象作为构造参数

    @Test
    public void run() {
        MyThread myThread = new MyThread();
        Thread thread = new Thread(myThread);
        thread.start();
    }
    

    3. 实现 Runnable 接口

    @Slf4j
    public class MyThread implements Runnable {
        @Override
        public void run() {
            log.info("run...");
        }
    }
    

    调用

    @Test
    public void run() {
        MyThread myThread = new MyThread();
        // 创建线程对象
        Thread thread = new Thread(myThread, "test");
        thread.start();
    }
    

    打印结果:

    18:33:39.150 [test] INFO juc.MyThread - run...
    

    3.2 匿名内部类方式

    @Test
    public void run() {
        Runnable runnable = new Runnable() {
            @Override
            public void run() {
                log.info("run...");
            }
        };
        Thread thread = new Thread(runnable);
        Thread thread2= new Thread(runnable, "t2");
    
        thread.start();
        thread2.start();
    }
    

    打印结果:

    18:37:00.045 [Thread-1] INFO juc.JUCDemo - run...
    18:37:00.045 [t2] INFO juc.JUCDemo - run...
    

    4. 实现 Callable 接口

    @Test
    public void run() {
        Callable<Integer> callable = new Callable<Integer>() {
            @Override
            public Integer call() throws Exception {
                return Stream.iterate(1, n -> n + 1)
                        .limit(100)
                        .reduce(0, Integer::sum);
            }
        };
    
        // Callable 有返回值,需要 FutureTask 来接收执行结果
        FutureTask<Integer> task = new FutureTask<>(callable);
        new Thread(task).start();
    
        Integer result = null;
        try {
            // 接收运行的结果: get()是阻塞的,等call()执行完才会返回
            result = task.get();
        } catch (Exception e) {
            e.printStackTrace();
        }
        
        System.out.println(result);
    }
    

    5. Runable vs Callable

    • Runnable 的 run() 无返回值
    • Callable 的 call() 有返回值,并且有声明异常
    public interface Runnable {
        public abstract void run();
    }
    public interface Callable<V> {
        V call() throws Exception;
    }
    

    6. 其他

    6.1 设置线程名称

    方式一:直接 setName()

    MyThread thread = new MyThread();
    thread.start();
    thread.setName("Thread name");
    

    方式二:在构造方法里设置

    public class MyThread extends Thread {
        public MyThread(String name) {
            super(name);
        }
    }
    

    相关文章

      网友评论

          本文标题:JUC 之线程创建

          本文链接:https://www.haomeiwen.com/subject/gjglwdtx.html