美文网首页
Java 线程基础

Java 线程基础

作者: Tinyspot | 来源:发表于2022-09-01 06:44 被阅读0次

    1. 进程 vs 线程

    • 进程:正在运行的程序,是资源分配的最小单位(基本单位)
    • 线程是CPU调度的最小单位
      • 轻量级进程
      • 进程中的一条执行路径,是 CPU 的基本调度单位
    • 一个进程由一个或多个线程组成,彼此间完成不同的工作,同时执行,称为多线程
    • 一台设备能并行执行多少个线程取决于CPU核心数

    例如:Java 虚拟机是一个进程,当中默认包含主线程(main),可通过代码创建多个独立线程,与 main 并发执行

    1.1 线程的特点

    • 线程抢占式执行
    • 在单核 CPU 中,宏观上同时执行,微观上顺序执行

    1.2 并发与并行

    • 并发指一个 CPU 同时处理多个任务(轮流使用 CPU 时间片)
    • 并行是指多个 CPU 或多核 CPU 同时处理多个不同的任务

    2. 创建线程

    • 在 JDK 中代表线程的就只有 Thread 类
    • 线程的执行单元是 run(),可以通过继承 Thread 然后重写 run() 实现,也可以实现 Runnable 接口

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

    2.1 示例一:继承 Thread

    public class MyThread extends Thread {
        @Override
        public void run() {
          // // this.getId() 和 this.getName() 有局限性,必须是 extends Thread 才能使用,因为这是父类中的方法
          System.out.println("线程id: " + this.getId() + "; 线程name: " + this.getName() + "; Thread name: " + Thread.currentThread().getName());
        }
    }
    MyThread thread = new MyThread();
    thread.start();
    

    匿名内部类方式:

    • 子类重写父类的 run()
    • 语法 new 父类() { 子类内容 }; 匿名类是一个表达式,因此在定义的最后用分号;结束
    new Thread() {
        @Override
        public void run(){
            System.out.println("threa start...");
        }
    }.start();
    

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

    public static void main(String[] args) {
        MyThread myThread = new MyThread();
        Thread thread = new Thread(myThread);
        thread.start();
    }
    

    2.2 示例二:实现 Runnable

    MyThread myThread = new MyThread();
    // 创建线程对象
    Thread thread = new Thread(myThread, "Thread name");
    thread.start();
    
    public class MyThread implements Runnable {
        @Override
        public void run() {
            System.out.println("run...");
        }
    }
    

    匿名内部类方式

    public static void main(String[] args) {
        Runnable runnable = new Runnable() {
            @Override
            public void run() { // ... }
        };
        Thread thread = new Thread(runnable);
        Thread thread2= new Thread(runnable, "t2");
    
        thread.start();
        thread2.start();
    }
    

    2.3 示例三:实现 Callable(Since: 1.5)

    public static void main(String[] args) throws Exception {
        Callable<Integer> callable = new Callable<Integer>() {
            @Override
            public Integer call() throws Exception {
                int sum = 0;
                for (int i = 0; i <= 100; i++) {
                    sum += i;
                }
                return sum;
            }
        };
    
        // Callable 有返回值,需要 FutureTask 来接收执行结果
        FutureTask<Integer> task = new FutureTask<>(callable);
        new Thread(task).start();
    
        // 接收运行的结果
        // get() 是阻塞的,等 call() 执行完才会返回
        Integer result = task.get();
        System.out.println(result);
    }
    

    3. Runable / Callable / Future

    3.1 Runable vs Callable

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

    3.2 Future 接口

    • Future 表示将要完成任务的结果
    public interface Future<V> {
        // get() 以阻塞形式等待 Future 中的异步处理结果
        V get() throws InterruptedException, ExecutionException;
        V get(long timeout, TimeUnit unit)  throws InterruptedException, ExecutionException, TimeoutException;
    }
    
    public class FutureTask<V> implements RunnableFuture<V> {
        public FutureTask(Callable<V> callable) {
            if (callable == null)
                throw new NullPointerException();
            this.callable = callable;
            this.state = NEW;       // ensure visibility of callable
        }
    }
    
    public interface RunnableFuture<V> extends Runnable, Future<V> {
        void run();
    }
    

    4. 其他

    4.1 设置线程名称

    直接 setName() 或者 在构造方法里设置

    // 方式一:直接 setName()
    MyThread thread = new MyThread();
    thread.start();
    thread.setName("Thread name");
    
    // 方式二:使用构造方法
    public class MyThread extends Thread {
        public MyThread(String name) {
            super(name);
        }
    }
    

    4.2 将 Callable 放入线程池执行

    public class Demo {
        public void test() throws Exception {
            ExecutorService executorService = Executors.newFixedThreadPool(3);
            Callable<Integer> caller = new Caller(10);
            Future<Integer> future = executorService.submit(caller);
            System.out.println(future.get());
            executorService.shutdown();
        }
    
        class Caller implements Callable<Integer> {
            private Integer sum = 0;
    
            public Caller(Integer sum) {
                this.sum = sum;
            }
    
            @Override
            public Integer call() throws Exception {
                for (int i = 0; i <= 100; i++) {
                    sum += i;
                }
                return sum;
            }
        }
    }
    

    相关文章

      网友评论

          本文标题:Java 线程基础

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