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. F5 BIG-IP之二LTM术语

    Node : Pool:中有设置负载均衡方式 Virtual Server :监听客户端请求的 根据 IP 和 端口号 Profile: VS 调用 Profile

  2. 03 - CDH 6.3.x 安装

    CDH 6.3.x 离线安装 环境 CDH 6.3.1 CentOS 7 官方文档 修改主机名,配置host文件 # 根据个人需要修改主机名称 hostnamectl set-hostname nod ...

  3. python库之——sklearn

    机器学习库sklearn 官方documentation(资料)中分为不同的部分: 其中我们主要讲User Guide(机器学习算法理论介绍).API(程序实现方法): 一.User Guide ht ...

  4. Null Hypotheses| Alternative Hypotheses|Hypothesis Test|Significance Level|two tailed |one tailed|

    9.1 The Nature of Hypothesis Testing Over the years, however, null hypothesis has come to mean simpl ...

  5. hadoop datanode 启动正常,但master无法识别(50030不显示datanode节点)

    start-all.sh 启动 坑爹 找不出错 试了各种办法,重新formaet 查看 集群ID是否相同.都无效 日志也没看到错 按官网方法手动一步步启,问题照旧 master节点,yarn name ...

  6. 转:B树和B+树的插入、删除图文详解

    如需转载,请注明出处 http://www.cnblogs.com/nullzx/ 1. B树 1. B树的定义 B树也称B-树,它是一颗多路平衡查找树.我们描述一颗B树时需要指定它的阶数,阶数表示了 ...

  7. python 同步与异步的性能区别及实例

    同步与异步的性能区别  1. #coding:utf-8 import gevent def task(pid): """ Some non-deterministic ...

  8. Gre 隧道与 Keepalived

    这一篇文章是做了不少功课的. 什么是 Gre 隧道 什么是 Vrrp KeepAlived 是什么 用Keepalived 怎么玩 附录 什么是 Gre 隧道 GRE 隧道是一种 IP-2-IP 的隧 ...

  9. 用Python拨打电话

    用python拨打电话,先看小视频 跟selenium操作浏览器原理类似,这是用appium操作移动设备的一个自动化功能,自娱自乐,主要是通过小案例引出相关技术 一.环境配置: 1.安装 jdk 1. ...

  10. 给文本中的url加超级链接,同时滤过已加过链接的url

    /** * 给文本中的url加超级链接,同时滤过已有链接的url * @param string $str [description] * @return [type] [description] * ...