Netty的并发编程实践4:线程安全类的应用
在JDK1.5的发行版本中,Java平台新增了java.util.concurrent,这个包中提供了一系列的线程安全集合、容器和线程池,利用这些新的线程安全类可以极大地降低Java多线程编程的难度,提升开发效率。
新的并发编程包中的工具可以分为如下4类。
◎ 线程池Executor Framework以及定时任务相关的类库,包括Timer等。
◎ 并发集合,包括List、Queue、Map和Set等。
◎ 新的同步器,例如读写锁ReadWriteLock等。
◎ 新的原子包装类,例如AtomicInteger等。
在实际编码过程中,我们建议通过使用线程池、Task(Runnable/Callable)、原子类和线程安全容器来代替传统的同步锁、wait和notify,以提升并发访问的性能、降低多线程编程的难度。
下面,针对新的线程并发包在Netty中的应用进行分析和说明,以期为大家的学习和应用提供指导。
首先看下线程安全容器在Netty中的应用。NioEventLoop是I/O线程,负责网络读写操作,同时也执行一些非I/O的任务。例如事件通知、定时任务执行等,因此,它需要一个任务队列来缓存这些Task。它的任务队列定义如图21-12所示。
图21-12 线程任务队列定义
它是一个ConcurrentLinkedQueue,我们看它的API说明,如图21-13所示。
图21-13 ConcurrentLinkedQueue线程安全文档
DOC文档明确说明这个类是线程安全的,因此,对它进行读写操作不需要加锁。下面我们继续看下队列中增加一个任务,如图21-14所示。
图21-14 ConcurrentLinkedQueue新增Task
读取任务,也不需要加锁,如图21-15所示。
图21-15 ConcurrentLinkedQueue读取Task
JDK的线程安全容器底层采用了CAS、volatile和ReadWriteLock实现,相比于传统重量级的同步锁,采用了更轻量、细粒度的锁,因此,性能会更高。合理地应用这些线程安全容器,不仅能提升多线程并发访问的性能,还能降低开发难度。
下面我们看看线程池在Netty中的应用,打开SingleThreadEventExecutor看它是如何定义和使用线程池的。
首先定义了一个标准的线程池用于执行任务,代码如下。
接着对它赋值并且进行初始化操作,代码如下。
执行任务代码如图21-16所示。
图21-16 SingleThreadEventExecutor任务执行
我们发现,实际上执行任务就是先把任务加入到任务队列中,然后判断线程是否已经启动循环执行,如果不是则需要启动线程。启动线程代码如图21-17所示。
实际上就是执行当前线程的run方法,循环从任务队列中获取Task并执行,我们看它的子类NioEventLoop的run方法就能一目了然,如图21-18所示。
如图21-19中框线内所示,循环从任务队列中获取任务并执行。
图21-17 SingleThreadEventExecutor启动新的线程
图21-18 按照I/O任务比例执行任务Task
图21-19 循环从任务队列中获取任务Task并执行
Netty对JDK的线程池进行了封装和改造,但是,本质上仍然是利用了线程池和线程安全队列简化了多线程编程。
Netty的并发编程实践4:线程安全类的应用的更多相关文章
- Netty的并发编程实践5:不要依赖线程优先级
当有多个线程同时运行的时候,由线程调度器来决定哪些线程运行.哪些等待以及线程切换的时间点,由于各个操作系统的线程调度器实现大相径庭,因此,依赖JDK自带的线程优先级来设置线程优先级策略的方法是错误和非 ...
- Netty的并发编程实践2:volatile的正确使用
长久以来大家对于volatile如何正确使用有很多的争议,既便是一些经验丰富的Java设计师,对于volatile和多线程编程的认识仍然存在误区.其实,volatile的使用非常简单,只要理解了Jav ...
- Netty的并发编程实践1:正确使用锁
很多刚接触多线程编程的开发者,虽然意识到了并发访问可变变量需要加锁,但是对于锁的范围.加锁的时机和锁的协同缺乏认识,往往会导致出现一些问题.下面笔者就结合Netty的代码来讲解下这方面的知识. 打开F ...
- Netty的并发编程实践3:CAS指令和原子类
互斥同步最主要的问题就是进行线程阻塞和唤醒所带来的性能的额外损耗,因此这种同步被称为阻塞同步,它属于一种悲观的并发策略,我们称之为悲观锁.随着硬件和操作系统指令集的发展和优化,产生了非阻塞同步,被称为 ...
- [Java 并发] Java并发编程实践 思维导图 - 第二章 线程安全性
依据<Java并发编程实践>一书整理的思维导图.
- 并发编程实践五:ReentrantLock
ReentrantLock是一个可重入的相互排斥锁,实现了接口Lock,和synchronized相比,它们提供了同样的功能.但ReentrantLock使用更灵活.功能更强大,也更复杂.这篇文章将为 ...
- 并发编程实践三:Condition
Condition实例始终被绑定到一个锁(Lock)上.Lock替代了Java的synchronized方法,而Condition则替代了Object的监视器方法,包含wait.notify和noti ...
- 【Java并发编程六】线程池
一.概述 在执行并发任务时,我们可以把任务传递给一个线程池,来替代为每个并发执行的任务都启动一个新的线程,只要池里有空闲的线程,任务就会分配一个线程执行.在线程池的内部,任务被插入一个阻塞队列(Blo ...
- Java并发编程实践
最近阅读了<Java并发编程实践>这本书,总结了一下几个相关的知识点. 线程安全 当多个线程访问某个类时,不管运行时环境采用何种调度方式或者这些线程将如何交替执行,并且在主调代码中不需要任 ...
随机推荐
- aop难点解析。
静态织入和动态织入的区别? 需求示例:假设有一个包,一个包当中有一个方法,我们想在这个方法的前后,加上环绕. 那么怎么加呢? 把知道的都说一遍. 1.建立JsonService 2.建立JSONASP ...
- Django中url的生成过程详解
在前面我们知道,Django启动之前会执行admin.py中的autodiscover()方法. def autodiscover(): autodiscover_modules('admin', r ...
- Go笔记-指针
Go 语言的取地址符是 &,放到一个变量前使用就会返回相应变量的内存地址 一个指针变量可以指向任何一个值的内存地址 它指向那个值的内存地址,在 32 位机器上占用 4 个字节,在 64 位机器 ...
- HDU 4825 Xor sum
trie树的异或和问题 本题是一道经典题,使用trie树维护所给出的集合,我们知道等比数列前n项的和比第n+1项小,所以本题可以使用贪心策略,对于每一个询问,我们从高位向低位匹配,寻找最大异或值,向下 ...
- 51NOD 1220 约数之和 [杜教筛]
1220 约数之和 题意:求\(\sum_{i=1}^n \sum_{j=1}^n \sigma_1(ij)\) \[ \sigma_0(ij) = \sum_{x\mid i}\sum_{y\mi ...
- [实例]JAVA调用微信接口发送图文消息,不用跳到详情页
package com.test; import java.io.IOException; import java.io.InputStream; import java.io.OutputStrea ...
- Python中append和extend的区别
编者注:本文主要参考了<Python核心编程(第二版)> 网上有很多对这两个函数的区别讲解,但我觉得都讲的不是很清楚,记忆不深刻.这样解释清楚且容易记住. list.append(obje ...
- C#小笔记:单例模式
双重锁定: public class Singleton { private static Singleton instance; private static readonly object syn ...
- Angular Pipe的应用
1-在html文件中使用管道:(管道符合使用,用':'号隔开) ①页面中添加: <div class="table_content" *ngFor="let ite ...
- ireport报表学习
常用组件介绍: 制作一个报表一般四个组件比较常用,下面分别介绍 Rectangle:用于画表格的样式,整个表格的样式使用次组件做出来的,本控件表现为一个黑色矩形框,多个黑色矩形框排在一起可以组合出来任 ...