很多刚接触多线程编程的开发者,虽然意识到了并发访问可变变量需要加锁,但是对于锁的范围、加锁的时机和锁的协同缺乏认识,往往会导致出现一些问题。下面笔者就结合Netty的代码来讲解下这方面的知识。

打开ForkJoinTask,我们学习一些多线程同步和协作方面的技巧。首先是当条件不满足时阻塞某个任务,直到条件满足后再继续执行,代码如图21-4所示。

重点看框线中的代码,首先通过循环检测的方式对状态变量status进行判断,当它的状态大于等于0时,执行wait(),阻塞当前的调度线程,直到status小于0,唤醒所有被阻塞的线程,继续执行。这个方法有以下三个多线程的编程技巧需要说明。

图21-4  多线程协作

(1)wait方法用来使线程等待某个条件,它必须在同步块内部被调用,这个同步块通常会锁定当前对象实例。下面是这个模式的标准使用方式。

synchronized(this)

{

While(condition)

Object.wait;

......

}

(2)始终使用wait循环来调用wait方法,永远不要在循环之外调用wait方法。这样做的原因是尽管并不满足被唤醒条件,但是由于其他线程调用notifyAll()方法会导致被阻塞线程意外唤醒,此时执行条件并不满足,它将破坏被锁保护的约定关系,导致约束失效,引起意想不到的结果。

(3)唤醒线程,应该使用notify还是notifyAll?当你不知道究竟该调用哪个方法时,保守的做法是调用notifyAll唤醒所有等待的线程。从优化的角度看,如果处于等待的所有线程都在等待同一个条件,而每次只有一个线程可以从这个条件中被唤醒,那么就应该选择调用notify。

当多个线程共享同一个变量的时候,每个读或者写数据的操作方法都必须加锁进行同步,如果没有正确的同步,就无法保证一个线程所做的修改被其他线程共享。未能同步共享变量会造成程序的活性失败和安全性失败,这样的失败通常是难以调试和重现的,它们可能间歇性地出问题,可能随着并发的线程个数增加而失败,也可能在不同的虚拟机或者操作系统上存在不同的失败概率。因此,务必要保证锁的正确使用。下面这个案例,就是个典型的错误应用。

int size = 0;

public synchronized void increase()

{

size++;

}

public int current()

{

Return size;

}

Netty的并发编程实践1:正确使用锁的更多相关文章

  1. Netty的并发编程实践4:线程安全类的应用

    在JDK1.5的发行版本中,Java平台新增了java.util.concurrent,这个包中提供了一系列的线程安全集合.容器和线程池,利用这些新的线程安全类可以极大地降低Java多线程编程的难度, ...

  2. Netty的并发编程实践3:CAS指令和原子类

    互斥同步最主要的问题就是进行线程阻塞和唤醒所带来的性能的额外损耗,因此这种同步被称为阻塞同步,它属于一种悲观的并发策略,我们称之为悲观锁.随着硬件和操作系统指令集的发展和优化,产生了非阻塞同步,被称为 ...

  3. Netty的并发编程实践2:volatile的正确使用

    长久以来大家对于volatile如何正确使用有很多的争议,既便是一些经验丰富的Java设计师,对于volatile和多线程编程的认识仍然存在误区.其实,volatile的使用非常简单,只要理解了Jav ...

  4. Netty的并发编程实践5:不要依赖线程优先级

    当有多个线程同时运行的时候,由线程调度器来决定哪些线程运行.哪些等待以及线程切换的时间点,由于各个操作系统的线程调度器实现大相径庭,因此,依赖JDK自带的线程优先级来设置线程优先级策略的方法是错误和非 ...

  5. 并发编程实践五:ReentrantLock

    ReentrantLock是一个可重入的相互排斥锁,实现了接口Lock,和synchronized相比,它们提供了同样的功能.但ReentrantLock使用更灵活.功能更强大,也更复杂.这篇文章将为 ...

  6. Java并发编程实践

    最近阅读了<Java并发编程实践>这本书,总结了一下几个相关的知识点. 线程安全 当多个线程访问某个类时,不管运行时环境采用何种调度方式或者这些线程将如何交替执行,并且在主调代码中不需要任 ...

  7. [Java 并发] Java并发编程实践 思维导图 - 第一章 简单介绍

    阅读<Java并发编程实践>一书后整理的思维导图.

  8. [Java 并发] Java并发编程实践 思维导图 - 第二章 线程安全性

    依据<Java并发编程实践>一书整理的思维导图.

  9. 并发编程实践三:Condition

    Condition实例始终被绑定到一个锁(Lock)上.Lock替代了Java的synchronized方法,而Condition则替代了Object的监视器方法,包含wait.notify和noti ...

随机推荐

  1. 使用clipboard.js实现复制内容至剪贴板

    下载插件 clipboard.js是不依赖flash,实现复制内容至剪贴板的js插件.下载clipboard.js的压缩包,根据需要选择dist目录下的压缩或未压缩版. github地址:https: ...

  2. c# 简单实现 插件模型 反射方式

    利用反射方式实现插件模型,wpf控件作为插件,然后用另外的窗体加载. 首先定义插件接口: public interface IUserControlLevel1 { string PluginName ...

  3. 一次saltstack环境变量的坑

    现场环境: salt-minion端: ip:10.0.3.149     环境:使用 nvm装的nodejs    受用nodejs自带的npm 安装pm2 sal-master端: IP:10.0 ...

  4. Linux命令pmap

    jmap可以查看Java程序的堆内存使用情况,pmap可以查看Linux上运行的进程的内存使用情况. 查看Linux上运行的进程的内存使用情况,可以使用jmap,top,ps命令. top命令本身也比 ...

  5. BZOJ 1415: [Noi2005]聪聪和可可 [DP 概率]

    传送门 题意:小兔子乖乖~~~ 题意·真:无向图吗,聪抓可,每个时间聪先走可后走,聪一次可以走两步,朝着里可最近且点编号最小的方向:可一次只一步,等概率走向相邻的点或不走 求聪抓住可的期望时间 和游走 ...

  6. nginx截获客户端请求

    使用nginx可以直接截获客户端请求,以下是最近收集的一些判断截获的信息的配置,为查看方便记录如下: 1.根据UA和cookie判断当前是移动端还是PC端访问: if ($http_host !~ & ...

  7. 用es6的Array.reduce()方法计算一个字符串中每个字符出现的次数

    有一道经典的字符串处理的问题,统计一个字符串中每个字符出现的次数. 用es6的Array.reduce()函数配合“...”扩展符号可以更方便的处理该问题. s='abananbaacnncn' [. ...

  8. 【Unity3D技术文档翻译】第1.5篇 本地使用 AssetBundles

    上一章:[Unity3D技术文档翻译]第1.4篇 AssetBundle 依赖关系 本章原文所在章节:[Unity Manual]→[Working in Unity]→[Advanced Devel ...

  9. Linux 6.4 设置yum 为centOS源

    一. 删除Redhat 自带的yum // root 用户执行 rpm -aq|grep yum|xargs rpm -e --nodeps 二 .下载CentOS 的 yum 安装文件 wget h ...

  10. @Scope注解

    @Scope(value=ConfigurableBeanFactory.SCOPE_PROTOTYPE)这个是说在每次注入的时候回自动创建一个新的bean实例 @Scope(value=Config ...