Java 并发系列之一

Java 并发系列之一

简单的总结了一些 Java 经常使用的集合以后,发现许多集合都针对多线程提供了支持,好比 ConcurrentHashMap 使用分段锁来提升多线程环境下的性能表现与安全表现。因此我打算接着对 Java 并发的相关内容作一个简单总结。java

线程与进程

进程是操做系统分配资源的基本单位,也就是说进程是运行中的程序。安全

线程是进程中的基本执行单元,每一个进程都至少拥有一个线程。线程不独立拥有操做系统资源,线程共享进程的操做系统资源。多线程

处理并发问题为何使用多线程而不是多进程,在我看来主要有两点。一是进程间通讯难度大于线程间通讯,会增长开发难度,二是线程间切换效率高于进程间切换,选择多线程更适合并发场景。并发

线程的生命周期

这里咱们只简单介绍线程 new->Runnable->Running->Dead 这个流程,不考虑 Block 的状况。ide

  1. 当咱们建立一个 Thread 对象时,这个线程就进入了 new 的状态。
  2. 当时机成熟,咱们调用这个对象的 start() 方法时,这个线程就进入了 Runnable 的状态。
  3. 而后这个线程就会等待 CPU 资源,若是获取到 CPU 资源就会自动运行。
  4. 运行结束后线程就会进入到 Dead 状态。

须要注意的是一个 Thread 对象只有一次调用 start() 方法的机会,不管这个线程是否顺利执行结束。函数

建立线程

建立线程也就是线程生命周期中的 new 状态。在 Java 中建立线程有 3 中方式:性能

  1. 继承 Thread 类并重写 run 方法
  2. 实现 Runnable 接口
  3. 实现 Callable 接口

继承 Thread 类来建立线程

使用继承 Thread 的方式能够直接在 run 方法中利用 this 来获取当前线程的信息,而不须要经过 Thread 类的静态方法 currentThread() 方法来获取当前的线程。this

public class MyThread extends Thread {
    @Override
    public void run() {
        System.out.println(this.getName()+"正在运行");
    }
}

public static void main(String[] args) {
    Thread thread = new MyThread();
    thread.start();
}
//输出结果:Thread-0 正在运行

若是想要快速实现一个匿名的类来执行某个简单操做的话,能够用下面的方式:操作系统

public static void main(String[] args) {
    new Thread() {
        @Override
        public void run() {
            System.out.println(this.getName() + "正在执行");
        }
    }.start();
}
//输出结果:Thread-0 正在运行

实现 Runnable 接口来建立线程

因为 Java 是不支持多继承的,因此若是要继承 Thread 类之外的类,使用 Runnable 来实现或许是个不错的选择。线程

public class MyRunnable implements Runnable {
    @Override
    public void run() {
        System.out.println(Thread.currentThread().getName()+"正在运行");
    }
}

public static void main(String[] args) {
    Runnable runnable = new MyRunnable();
    Thread thread = new Thread(runnable);
    thread.start();
}
//输出结果:Thread-0 正在运行

其实 Runnable 接口只包含一个 run 方法,本质上仍是经过重写 Thread 类的 run 方法来达到建立线程的目的。Runnable 仍是一个函数式接口,因此想要声明一个匿名的 Thread 类还能经过下面的方式:

public static void main(String[] args) {
    new Thread(() -> {
        System.out.println(Thread.currentThread().getName() + "正在运行");
    }).start();
}
//输出结果:Thread-0 正在运行

实现 Callable 接口来建立线程

上面两种建立线程的方式都是不支持返回值的,若是须要线程在执行以后提供返回值,就能够经过 Callable 来建立线程。使用 Callable 建立线程分为如下几个步骤:

  1. 建立类实现 Callable 接口的 call() 方法
  2. 使用 FutureTask 来包装上一步建立的类
  3. 使用 FutureTask 来建立 Thread 类
  4. 使用 FutureTask 对象的 get() 方法来获取返回值
public class MyCallable implements Callable<Integer> {
    @Override
    public Integer call() throws Exception {
        System.out.println(Thread.currentThread().getName()+"正在运行");
        return 316495132;
    }
}

public static void main(String[] args) 
    throws ExecutionException,InterruptedException {
    Callable callable = new MyCallable();
    FutureTask<Integer> futureTask = new FutureTask<>(callable);
    Thread thread = new Thread(futureTask);
    thread.start();
    System.out.println("返回值为:" + futureTask.get());
}
//输出结果:
//Thread-0 正在运行
//返回值为:316495132

小结

  1. 若是没有特殊的需求,实现 Runnable 接口或许是一个比较好的选择
  2. 若是须要线程执行完成后提供返回值,就只能选择继承 Callable 接口
相关文章
相关标签/搜索