先行发生原则

  • 程序顺序原则:一个线程内保证语义的串行性
  • volatile:volatile变量的写,先发生于读,这保证了volatile变量的可见性
  • 锁规则:解锁必然发生在随后的加锁前
  • 传递性:A优先于B B优先于C 则A优先于C
  • 线程的start方法优先于它的每一个动作
  • 线程的所有操作先于线程的终结 Thread.join()
  • 对象的构造函数执行、结束先于finalize()方法
  • 线程的中断 interrupt()先于被中断线程的代码

ReentrantLock:

  • lock()
  • lockInterruptibly()
  • tryLock()  //return instantly
  • tryLock(long time, TimeUnit unit)  //after time return
  • unlock()

synchronized:

  • 指定加锁对象:对给定对象加锁
  • 作用于实例方法:相当于对当前实例加锁
  • 作用于静态方法:相当于对当前类加锁

Semaphore

信号量可以指定多个线程,同时访问某一个资源   这个例子中系统以5个线程一组为单位 访问doSomething()

final Semaphore semp = new Semaphore(5)

semp.acquire();
doSomething();
semp.release();


CountDownLatch

  • 构造函数接收一个整数作为参数,即当前这个计数器的计数个数
  • CountDownLatch.await()   CountDownLatch.countdown() //直到减少到指定的计数个数
  • BrokenBarrierException异常  比如当前计数器为10  而其中1个线程被中断,那么其他9个线程抛出BrokenBarrierException异常

CyclicBarrier

  • 与CountDownLatch功能类似  可以反复使用
  • 可以接收一个一个参数作为Runnable barrierAction --->当计数器完成一次计数后 系统会执行的动作
  • CyclicBarrier.await()会开始进行计数  达到指定数目 程序继续执行

notify 并不立刻释放对象锁,需要等待当前代码块执行完毕,即T1收到信号后,尝试获取对象锁,

但是此时方法并未结束故要等待代码块运行结束,再继续执行

Thread.sleep()由于中断而抛出异常 此时会清楚中断标记


无锁

  • 无锁是一种乐观策略,使用CAS(compare and swap)来鉴别线程冲突,如果发生冲突,就重试当前操作直到没有冲突为止。
  • CAS(V,E,N) V要更新的变量,E表示预期值,N表示心值
  • 仅当V=E时,才会将V设置为N  如果V!=E 说明已经有其他线程做了更新 当前线程什么也不做
  • CAS操作即使没有锁,也可以发现其他线程对当前线程的干扰,并进行恰当的处理。
  • 典型的一个特征 可能会包含一个无穷循环 无锁的并行总能保证有一个线程胜出

自旋锁

  • 当前线程未获得锁,系统进行一次赌博,假设不久的将来会得到这个锁,虚拟机会让当前线程做几个空循环,来等待获得锁

AtomicInteger

  • #final boolean compareAndSet(int expect, int u)  //如果当前值为expect 则设置为u
  • compareAndSet ----> unsafe.compareAndSwapInt(Objuect obj,long valueOffset,int expect,int update)
  • 不支持static字段
  • 其实CAS也算是有锁操作,只不过是由CPU来触发,比synchronized性能好的多。  ---http://www.jianshu.com/p/9f0ba2bab24e
  • 自己的应用程序无法使用Unsafe类 它是一个JDK内部使用的专属类

AtomicReference //保证修改对象引用时线程安全性

AtomicStampedReference //应用于“一次修改”  此时不仅比对值 也要比对时间戳


AtomicIntegerArray  AtomicLongArray AtomicReferenceArray


AtomicIntegerFieldUpdater

  • 利用反射机制
  • 变量需要定义为 volatile 且不能是private static 类型

Java内存模型规定了所有的变量都存储在主内存中,每条线程还有自己的工作内存,线程的工作内存中保存了该线程使用到的变量的主内存副本拷贝,线程对变量的所有操作都必须在工作内存中进行,而不能直接读写主内存中的变量。不同的线程之间也无法直接访问对方工作内存中的变量,线程间变量值的传递均需要通过主内存来完成。

Ps这里的主内存、工作内存与java内存模型中的堆、栈、方法区不是同一个层次的内存划分。


    为什么说Java线程优先级不靠谱?

Java的线程是被映射到系统的原生线程实现的,最终线程调度还是由操作系统说了算,很多操作系统提供的优先级小于Java线程优先级的个数,此时就会出现几个不同优先级而在操作系统层面相同的情况。Ps如果要阻塞或唤醒一条线程,都需要操作系统来帮忙完成,这就需要从用户态切换到核心态中,因此状态转换需要耗费更多的处理器时间。

除此之外,优先级可能会被系统自行改变,windows中有一个“优先级推进器”,当系统发现一个线程被执行得特别勤奋努力,可能会越过线程优先级去为它分配执行时间。

乐观锁

原子类的getAndIncrement()底层就是通过CAS实现的,无锁同步。但是可能会出现ABA问题,可以使用“版本号”解决这个问题,但是大部分情况ABA不会意向并发的正确性,如果真的需要解决ABA问题,改用传统的互斥同步可能会比原子类更高效。

自旋锁

有些时候,共享数据的锁定状态只会持续很短的一段时间,为了这段时间去挂起和恢复线程并不值得,如果物理机器有一个以上的处理器(对处理器数量有要求),能让两个或以上的线程同时并行,我们就可以让后面请求锁的线程稍等一会儿,但不放弃处理器的执行时间,让线程执行一个忙循环(自旋),这就是自旋锁。

优缺点,如果锁被占用的时间很短,自旋等待的效果会非常好,反之如果锁被占用的时间很长,那么自旋的线程只会白白消耗处理器资源,反而会带来性能的浪费。JDK1.6引入了自适应的自旋锁,意味着自旋的时间不再固定额,而是由前一次在同一个锁上的自旋时间以及锁的拥有者的状态来决定。如果在同一个锁对象上,自旋等待刚刚成功获得锁,并且持有锁的线程正在运行中,那么虚拟机会认为这次自旋也很有可能再次成功,进而它将允许自旋等待持续相对更长的时间。另一方面,如果对于某个锁,自旋很少成功过,那在以后要获取这个锁时将可能省略掉自旋过程,避免浪费处理器资源。

JAVA多线程---高并发程序设计的更多相关文章

  1. Java 多线程高并发编程 笔记(一)

    本篇文章主要是总结Java多线程/高并发编程的知识点,由浅入深,仅作自己的学习笔记,部分侵删. 一 . 基础知识点 1. 进程于线程的概念 2.线程创建的两种方式 注:public void run( ...

  2. Java多线程高并发学习笔记(二)——深入理解ReentrantLock与Condition

    锁的概念 从jdk发行1.5版本之后,在原来synchronize的基础上,增加了重入锁ReentrantLock. 本文就不介绍synchronize了,有兴趣的同学可以去了解一下,本文重点介绍Re ...

  3. Java多线程高并发学习笔记(一)——Thread&Runnable

    进程与线程 首先来看百度百科关于进程的介绍: 进程是一个具有独立功能的程序关于某个数据集合的一次运行活动.它可以申请和拥有系统资源,是一个动态的概念,是一个活动的实体.它不只是程序的代码,还包括当前的 ...

  4. Java多线程高并发学习笔记——阻塞队列

    在探讨可重入锁之后,接下来学习阻塞队列,这边篇文章也是断断续续的写了很久,因为最近开始学ssm框架,准备做一个自己的小网站,后续可能更新自己写网站的技术分享. 请尊重作者劳动成果,转载请标明原文链接: ...

  5. java多线程高并发

    旭日Follow_24 的CSDN 博客 ,全文地址请点击: https://blog.csdn.net/xuri24/article/details/81293321 “高并发和多线程”总是被一起提 ...

  6. Java 多线程高并发编程 笔记(二)

    1. 单例模式(在内存之中永远只有一个对象) 1.1 多线程安全单例模式——不使用同步锁 public class Singleton { private static Singleton sin=n ...

  7. java多线程高并发知识总结

    1.      计算机系统 使用高速缓存来作为内存与处理器之间的缓冲,将运算需要用到的数据复制到缓存中,让计算能快速进行:当运算结束后再从缓存同步回内存之中,这样处理器就无需等待缓慢的内存读写了. 缓 ...

  8. java多线程高并发的学习

    1.      计算机系统 使用高速缓存来作为内存与处理器之间的缓冲,将运算需要用到的数据复制到缓存中,让计算能快速进行:当运算结束后再从缓存同步回内存之中,这样处理器就无需等待缓慢的内存读写了. 缓 ...

  9. JAVA多线程高并发学习笔记(三)——Callable、Future和FutureTask

    为什么要是用Callable和Future Runnable的局限性 Executor采用Runnable作为基本的表达形式,虽然Runnable的run方法能够写入日志,写入文件,写入数据库等操作, ...

随机推荐

  1. Servlet和Filter的url匹配以及url-pattern详解 及 filter 循环问题的解决

    Servlet和filter是J2EE开发中常用的技术,使用方便,配置简单,老少皆宜.估计大多数朋友都是直接配置用,也没有关心过具体的细节,今天遇到一个问题,上网查了servlet的规范才发现,ser ...

  2. node.js后台快速搭建在阿里云(二)(pm2和nginx篇)

    前期准备 阿里云服务器 node.js pm2 express nginx linux(推荐教程:鸟哥的私房菜) 简介 嗯……我只是个前端而已 在第一部分说完了express篇. 后面继续项目的部署, ...

  3. 编译安装dropbear

    author:JevonWei 版权声明:原创作品 dropbear也可实现ssh远程登录的作业 1. 安装开发包组 yum -y groupinstall "Development Too ...

  4. apache如何设置缓存

    基本介绍 httpd是一个比较经典的web服务器,也就是静态资源服务器,主要用来服务于一些静态的文件,例如css,js,html等文件,所谓的静态文件,也就是不需要通过服务器进行运行的文件. 在使用静 ...

  5. 通过业务系统的重构实践DDD

    最近新接了一个业务系统——社区服务系统,为了快速熟悉和梳理老系统的业务逻辑和代码,同时对老系统代码做一些优化,于是打算花上一个月时间不间断地对老系统服务进行重构.同时,考虑到社区业务的复杂性,想起了之 ...

  6. Maven(一)初识Maven

    前言 在这之前一直都有去看关于Maven的相关介绍,但是没有到真正要用的时候,自己总是以为懂了.其实真的感觉Maven并没有想象的那么简单! 那我们该怎么去学习maven呢?接下来我将从: 初步认识m ...

  7. Go数组、切片、映射的原理--简明解析

    数组.切片.映射是Golang的最重要的数据结构,下面是对这3种数据结构的一点个人总结: 一.数组 数组是切片和映射的基础数据结构. 数组是一个长度固定的数据类型,存储着一段具有相同数据类型元素的连续 ...

  8. Java中的异常和处理详解

    简介 程序运行时,发生的不被期望的事件,它阻止了程序按照程序员的预期正常执行,这就是异常.异常发生时,是任程序自生自灭,立刻退出终止,还是输出错误给用户?或者用C语言风格:用函数返回值作为执行状态?. ...

  9. Java GUI+mysql+分页查询

    1.要求 : 创建一个学生信息管理数据库 2.实现分页查询 代码如下: a)学生实体类: /** * @author: Annie * @date:2016年6月23日 * @description: ...

  10. 201521123107 《Java程序设计》第13周学习总结

    第13周-网络 1.本周学习总结 2.书面作业 1. 网络基础 1.1 比较ping www.baidu.com与ping cec.jmu.edu.cn,分析返回结果有何不同?为什么会有这样的不同? ...