Java 并发系列之一

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

线程与进程

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

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

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

线程的生命周期

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

  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() 方法来获取当前的线程。

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 接口

Java 并发系列之一的更多相关文章

  1. Java并发系列[1]----AbstractQueuedSynchronizer源码分析之概要分析

    学习Java并发编程不得不去了解一下java.util.concurrent这个包,这个包下面有许多我们经常用到的并发工具类,例如:ReentrantLock, CountDownLatch, Cyc ...

  2. Java并发系列[2]----AbstractQueuedSynchronizer源码分析之独占模式

    在上一篇<Java并发系列[1]----AbstractQueuedSynchronizer源码分析之概要分析>中我们介绍了AbstractQueuedSynchronizer基本的一些概 ...

  3. Java并发系列[3]----AbstractQueuedSynchronizer源码分析之共享模式

    通过上一篇的分析,我们知道了独占模式获取锁有三种方式,分别是不响应线程中断获取,响应线程中断获取,设置超时时间获取.在共享模式下获取锁的方式也是这三种,而且基本上都是大同小异,我们搞清楚了一种就能很快 ...

  4. Java并发系列[5]----ReentrantLock源码分析

    在Java5.0之前,协调对共享对象的访问可以使用的机制只有synchronized和volatile.我们知道synchronized关键字实现了内置锁,而volatile关键字保证了多线程的内存可 ...

  5. Java 并发系列之二:java 并发机制的底层实现原理

    1. 处理器实现原子操作 2. volatile /** 补充: 主要作用:内存可见性,是变量在多个线程中可见,修饰变量,解决一写多读的问题. 轻量级的synchronized,不会造成阻塞.性能比s ...

  6. java并发系列 - 第28天:实战篇,微服务日志的伤痛,一并帮你解决掉

    这是java高并发系列第28篇文章. 环境:jdk1.8. 本文内容 日志有什么用? 日志存在的痛点? 构建日志系统 日志有什么用? 系统出现故障的时候,可以通过日志信息快速定位问题,修复bug,恢复 ...

  7. java并发系列 - 第29天:高并发中常见的限流方式

    这是java高并发系列第29篇. 环境:jdk1.8. 本文内容 介绍常见的限流算法 通过控制最大并发数来进行限流 通过漏桶算法来进行限流 通过令牌桶算法来进行限流 限流工具类RateLimiter ...

  8. Java 并发系列之八:java 并发工具(4个)

    1. CountDownLatch 2. CyclicBarrier 3. Semaphore 4. Exchanger 5. txt java 并发工具 通俗理解 CountDownLatch 等A ...

  9. Java 并发系列之十:java 并发框架(2个)

    1. Fork/Join框架 2. Executor框架 3. ThreadPoolExecutor 4. ScheduledThreadPoolExecutor 5. FutureTask 6. t ...

随机推荐

  1. 四剑客(find&grep)

    一.find 简介: find相关:条件匹配表达式.选项表达式.动作表达式.组合条件表达式 1.1.语法格式 find   path   -option   [   -print ]   [ -exe ...

  2. 方差分析||MSA/MSE|

    应用统计学-方差分析 数值型数据使用线性回归来研究因素对因变量的影响.类别型数据使用方差分析来研究因素对因变量的影响.方差分析是使用方差比MSA/MSE来检验均值是否全相等,即相等是H0假设,而不全相 ...

  3. ip获取到城市

    <?phpfunction GetIP() {    if ($_SERVER["HTTP_X_FORWARDED_FOR"])        $ip = $_SERVER[ ...

  4. JAVA中String类以及常量池和常用方法

    一.String类的定义 String类特点:String 代表字符串.java程序中所有的字符串文字(例如:"abc")都被实现为String类的子类 String类特点:长度不 ...

  5. Typescript - 类型断言

    原文:TypeScript基本知识点整理 零.序言 类型断言,可以用来手动指定一个值的类型. 给我的感觉,和 java 中的强制类型转换很像. 常常和联合类型配合使用,如: // 错误示例 funct ...

  6. ranche2.0-CN

    遵循以下两步,快速运行rancher2.0 Step1:准备一台linux主机 准备一台64位Linux主机(推荐centos7.5+),至少4GB内存.安装Kubernetes支持的Docker-c ...

  7. 携程酒店DevOps测试实践

    作者简介 王幸福,携程酒店研发部高级测试经理,负责无线自动化测试相关工作.在测试框架和平台研发.移动测试.DevOps等领域有着丰富的经验. 如今很多大型互联网公司.创新型企业都在积极地进行DevOp ...

  8. 前进中的人工智能——聚焦Faculty Summit 2015人工智能主题研讨会

    Summit 2015人工智能主题研讨会" title="前进中的人工智能--聚焦Faculty Summit 2015人工智能主题研讨会"> 在近几年上映的科幻大 ...

  9. Ubuntu 14.10 进入单用户模式

    1. 开机,进入grub界面 2. 此时会有一个选项:Advanced Options for Ubuntu(ubuntu高级), 选中直接回车 3. 看到里面有很多选项,选中后面带recovery ...

  10. 康威定律(Conway's law)

    系统是设计该系统的组织结构的映射. Conway's law 最初是Conway在1967年发表的论文<How Do Committees Invent?>,然后 Fred Brooks ...