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. [LC] 149. Max Points on a Line

    Given n points on a 2D plane, find the maximum number of points that lie on the same straight line. ...

  2. highcharts 设置柱子之间的距离 柱子宽度

    plotOption : { column : { // 设置每个柱自身的宽度 pointWidth : // x轴每个点只用一个柱,则这个属性设置的是相邻的两个点的柱之间的间距. // 如果x轴每个 ...

  3. LeetCode No.67,68,69

    No.67 AddBinary 二进制求和 题目 给定两个二进制字符串,返回他们的和(用二进制表示). 输入为非空字符串且只包含数字 1 和 0. 示例 输入: a = "11", ...

  4. 点分治练习——BZOJ 2152

    做的第二道点分治的题目,比较裸,算是模板题吧(感觉比之前那题还简单点. 题目:BZOJ 2152 聪聪可可 题目大意:给出一棵树,求树上两点间长度为3的倍数(0也算)的路径数. 解题思路: 基本和PO ...

  5. mpvue框架的小程序和H5同时开发

    demo链接1.样式统一为了达到共用一套样式,采用px2rem-loader和px2rpx-loader进行代码的打包,细节如下: 由于UI设计图是在蓝湖上标注,宽度750,选择像素 PX 样式中直接 ...

  6. 最简化的DirectX 11开发环境的配置 VS2010

    转载自:http://blog.csdn.net/zhmxy555/article/details/7672101 在编写基于DirectX 11的应用程序之前,我们当然需要在IDE中加入Direct ...

  7. Web of science|SCIE|影响因子|SSCI|高被引论文|领域中热点论文|

    信息检索: 数据库 Web of science 影响因子只是针对期刊打分,并不是对文章打分.所以对文章评价可以看引用次数. SCIE (Science Citation Index Expanded ...

  8. 为什么有这么多人呼吁要取代Facebook?

    扎克伯格这段时间算是栽了,身为人生大赢家的他或许正在遭受最为灰暗的时刻.因为泄露5000万用户数据这一事件,Facebook股价暴跌且扎克伯格身家缩水.被英国与美国相关部门调查.#删除Facebook ...

  9. 吴裕雄--天生自然 R语言开发学习:主成分分析和因子分析(续一)

    #--------------------------------------------# # R in Action (2nd ed): Chapter 14 # # Principal comp ...

  10. 为啥Waymo和Uber间的官司,这么难界定?

    自动驾驶作为被众多巨头和创业者看好的技术及领域,已有众多企业涉足其中.在自动驾驶尚未完全落地.制定统一标准前,每家企业都在争分夺秒地进行研发,试图率先抢占自动驾驶的高地.毕竟一旦成功,就能够创造巨大的 ...