Java 并发系列之一
Java 并发系列之一
简单的总结了一些 Java 常用的集合之后,发现许多集合都针对多线程提供了支持,比如 ConcurrentHashMap 使用分段锁来提高多线程环境下的性能表现与安全表现。所以我打算接着对 Java 并发的相关内容做一个简单总结。
线程与进程
进程是操作系统分配资源的基本单位,也就是说进程是运行中的程序。
线程是进程中的基本执行单元,每个进程都至少拥有一个线程。线程不独立拥有操作系统资源,线程共享进程的操作系统资源。
处理并发问题为什么使用多线程而不是多进程,在我看来主要有两点。一是进程间通信难度大于线程间通信,会增加开发难度,二是线程间切换效率高于进程间切换,选择多线程更适合并发场景。
线程的生命周期

这里我们只简单介绍线程 new->Runnable->Running->Dead 这个流程,不考虑 Block 的情况。
- 当我们创建一个 Thread 对象时,这个线程就进入了 new 的状态。
- 当时机成熟,我们调用这个对象的 start() 方法时,这个线程就进入了 Runnable 的状态。
- 然后这个线程就会等待 CPU 资源,如果获取到 CPU 资源就会自动运行。
- 运行结束后线程就会进入到 Dead 状态。
需要注意的是一个 Thread 对象只有一次调用 start() 方法的机会,无论这个线程是否顺利执行结束。
创建线程
创建线程也就是线程生命周期中的 new 状态。在 Java 中创建线程有 3 中方式:
- 继承 Thread 类并重写 run 方法
- 实现 Runnable 接口
- 实现 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 创建线程分为以下几个步骤:
- 创建类实现 Callable 接口的 call() 方法
- 使用 FutureTask 来包装上一步创建的类
- 使用 FutureTask 来创建 Thread 类
- 使用 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
小结
- 如果没有特殊的需求,实现 Runnable 接口或许是一个比较好的选择
- 如果需要线程执行完成后提供返回值,就只能选择继承 Callable 接口
Java 并发系列之一的更多相关文章
- Java并发系列[1]----AbstractQueuedSynchronizer源码分析之概要分析
学习Java并发编程不得不去了解一下java.util.concurrent这个包,这个包下面有许多我们经常用到的并发工具类,例如:ReentrantLock, CountDownLatch, Cyc ...
- Java并发系列[2]----AbstractQueuedSynchronizer源码分析之独占模式
在上一篇<Java并发系列[1]----AbstractQueuedSynchronizer源码分析之概要分析>中我们介绍了AbstractQueuedSynchronizer基本的一些概 ...
- Java并发系列[3]----AbstractQueuedSynchronizer源码分析之共享模式
通过上一篇的分析,我们知道了独占模式获取锁有三种方式,分别是不响应线程中断获取,响应线程中断获取,设置超时时间获取.在共享模式下获取锁的方式也是这三种,而且基本上都是大同小异,我们搞清楚了一种就能很快 ...
- Java并发系列[5]----ReentrantLock源码分析
在Java5.0之前,协调对共享对象的访问可以使用的机制只有synchronized和volatile.我们知道synchronized关键字实现了内置锁,而volatile关键字保证了多线程的内存可 ...
- Java 并发系列之二:java 并发机制的底层实现原理
1. 处理器实现原子操作 2. volatile /** 补充: 主要作用:内存可见性,是变量在多个线程中可见,修饰变量,解决一写多读的问题. 轻量级的synchronized,不会造成阻塞.性能比s ...
- java并发系列 - 第28天:实战篇,微服务日志的伤痛,一并帮你解决掉
这是java高并发系列第28篇文章. 环境:jdk1.8. 本文内容 日志有什么用? 日志存在的痛点? 构建日志系统 日志有什么用? 系统出现故障的时候,可以通过日志信息快速定位问题,修复bug,恢复 ...
- java并发系列 - 第29天:高并发中常见的限流方式
这是java高并发系列第29篇. 环境:jdk1.8. 本文内容 介绍常见的限流算法 通过控制最大并发数来进行限流 通过漏桶算法来进行限流 通过令牌桶算法来进行限流 限流工具类RateLimiter ...
- Java 并发系列之八:java 并发工具(4个)
1. CountDownLatch 2. CyclicBarrier 3. Semaphore 4. Exchanger 5. txt java 并发工具 通俗理解 CountDownLatch 等A ...
- Java 并发系列之十:java 并发框架(2个)
1. Fork/Join框架 2. Executor框架 3. ThreadPoolExecutor 4. ScheduledThreadPoolExecutor 5. FutureTask 6. t ...
随机推荐
- 吴裕雄--天生自然 Hadoop大数据分布式处理:centos7修改系统时间、时区
cp -f /usr/share/zoneinfo/Asia/Shanghai /etc/localtime 修改完后需要重启.
- 之前项目使用的轻量的goweb框架
技术栈 go 主开发语言 基于 gorilla 项目 javascript(nodejs) 部分小工具,josn对象转换,自动编译 C#,codesmith通用代码生成,生成最基本的crud和翻页. ...
- CSS预处理技术
CSS自定义变量 这是一个实验中的标准,后续的具体写法和解析可能会有变动. 与Less|Sass等预处理器不同的是CSS变量带有语义效果,并且不需要额外的编译.因为其名称本身就包含了语义的信息,这使得 ...
- JavaScript replace() 方法+字符子集介绍(*)
重点两部分知识点 1.javascript replace()函数用法 以下replace用法转载自w3cSchool:http://www.w3school.com.cn/jsref/jsref_r ...
- StringUtil中isBlank(),idNUll,isEmpty的区别
StringUtils 方法的操作对象是 java.lang.String 类型的对象,是 JDK 提供的 String 类型操作方法的补充,并且是 null 安全的(即如果输入参数 String 为 ...
- VMware虚拟机克隆CentOS6.5后修改网卡
在学习zk伪分布式集群对的时候,第一次注意到克隆虚拟机后修改eth的ip地址,发现ip不是自己修改的ip,进而在询问下发现,当我们第一次登陆查看我们克隆的虚拟机ip时:我们看到的ip不是et ...
- Promise 的含义
Promise 的含义 Promise 是异步编程的一种解决方案,比传统的解决方案——回调函数和事件——更合理和更强大.它由社区最早提出和实现,ES6 将其写进了语言标准,统一了用法,原生提供了Pro ...
- SCSS 与 Sass 异同
SCSS 是 Sass 3 引入新的语法,其语法完全兼容 CSS3,并且继承了 Sass 的强大功能.也就是说,任何标准的 CSS3 样式表都是具有相同语义的有效的 SCSS 文件.另外,SCSS 还 ...
- 添砖加瓦:snappy无损压缩算法
一.简介 Snappy(旧称:Zippy)是Google基于LZ77的思路用C++语言编写的快速数据压缩与解压程序库,并在2011年开源.其目标并非最大压缩率或与其他压缩程序的兼容性,而是非常高的速度 ...
- Java NIO-09-零拷贝之 DMA
DMA 的好处 在介绍DMA之前我想问大家:我们为什么要引入DMA,DMA对我们有什么好处那? 计算机系统中各种常用的数据输入/输出方法有查询方式(包括无条件及条件传送方式)和中断方式,这些方式适用于 ...