当前位置:首页 > 开发 > 编程语言 > Java > 正文

Java并发编程学习笔记(1)

发表于: 2015-01-24   作者:aoyouzi   来源:转载   浏览次数:
摘要: 线程安全的代码本质上是管理队状态的访问,而且是共享/可变的状态. 一个对象的状态就是它的数据,存在状态变量中,还包括了任何会对它外部可见行为产生影响的数据.   共享:一个变量被对个线程访问 可变:变量的值会在其生命周期内可以改变 线程安全性的实质是在不可控制的并发访问中保护数据   一个对象是否应该是线程安全的取决于它是否会被多个线程访问. 线程安全的性质取决

线程安全的代码本质上是管理队状态的访问,而且是共享/可变的状态.

一个对象的状态就是它的数据,存在状态变量中,还包括了任何会对它外部可见行为产生影响的数据.

 

共享:一个变量被对个线程访问

可变:变量的值会在其生命周期内可以改变

线程安全性的实质是在不可控制的并发访问中保护数据

 

一个对象是否应该是线程安全的取决于它是否会被多个线程访问.

线程安全的性质取决于程序中如何使用对象,而非对象完成了什么

保证对象的线程安全性需要使用同步来协调对其可变状态的服务.

 

若多余一个线程访问某个变量,某线程还会修改其值,则必须使用同步机制来协调线程对变量的访问.

Java同步机制synchronized提供独占锁,还有volatile变量、显示锁、原子变量使用等。

 

设计线程安全的类时,优秀的面向对象技术——封装、不可变性及明确的不变约束会提供很多帮助。

 

线程安全性——一个类是线程安全的,是指在很多个线程访问时,类可以持续进行正确的行为。

 

线程安全的类封装了任何必要的同步,因此客户端无需自己提供。

对线程安全类的实例进行顺序或并发的一系列操作都不会导致实例处于无效状态。

 

无状态的线程永远是线程安全的——>多数的Servlet都是无状态的

 

多线程中的竞争条件——当计算的正确性依赖于运行时中相关的时序或多线程的交替时会产生竞争条件。

最常见的竞争条件是——检查再运行(check_and_act

常见用法:惰性初始化——延迟对象的初始化,直至程序真正使用它,且只初始化一次。(单例模式)

 

复合操作:为了保持线程安全性,操作必须原子的操作(自增操作不慎原子操作——读——改——写)

因此引入了锁机制(Java内置的原子性机制)

 

Java.util.concurrent.atomic包中包括了原子变量类,这些类用来实现数字和对象引用的原子状态的转换。但这些类只能添加一个状态变量,当多个状态变量时,需要用锁机制。

 

锁:Java提供了强制原子性的内置锁机制:synchronized块:分2部分,即:锁对象的引用+锁保护的代码块,形如:

Synchronizedlock{}

 

每个Java对象都可以隐式是一个用于同步的锁,这些内置的锁叫做“内部锁/监视器锁”。

执行线程进入synchronized块前会自动获得锁,无论通过正常退出还是抛出异常,线程都会在放弃对synchronized块的控制时自动释放锁。

获得锁的唯一方法:进入这个内部锁保护的同步块或方法。

 

内部锁在Java中是一个互斥锁,至多有一个线程可以拥有锁。

同一时间,只能有一个线程可以运行特定锁保护的代码块,因此,由用一个锁保护的synchronized块会各自原子的执行,不会相互干扰。

 

重进入:当一个线程请求其他线程正占有的锁时,请求线程会被阻塞;但内部锁是可重进入的。因此线程在试图获得她自己占有的锁时,请求会成功。

重进入意味着请求是基于“每线程”的,而非“每调用”的。

重进入的实现是通过为每个锁关联一个请求计数+一个占有它的线程。当计数=0时,表示锁未被占有;当线程请求一个未被占有的锁时,JVM记录锁的占有者,并把请求计数置为1;如果同一个线程再次请求这个锁,则计数+1;如果每次占用线程退出同步块,计数-1,直至计数=0,锁才释放。

如果没有重进入,子类同名同步方法调用父类同名同步方法会死锁。

 

锁用来保护状态:

仅仅用Synchronized块包装复合操作是不够的,如果用同步来协调访问变量,每次访问变量都要同步。用锁来协调访问变量时,每次访问变量都需要同一个锁。

 

对象的内部锁与他的状态之间没有内在的关系

 

即使获得了与对象关联锁也不能阻止其他线程访问这个对象——获得了对象的锁,唯一可做的事情是阻止其他线程再获得相同的锁。

 

常见的锁规则是在对象内部封装所有的可变状态。通过对象的内部锁来同步任何访问可变状态的代码路径,保护他在并发访问中的安全。

 

共享对象

Synchronized作用:原子操作或划定“临界区”+内存可见性

因此,我们不仅希望避免当一个线程修改其他线程正在使用的对象的状态,还希望当一个线程修改了对象状态后,其他线程能看到变化。

 

 

为了保证跨线程写入的内存可见性,必须使用同步机制(只要数据需要被跨线程共享,就进行恰当的同步)

 

当访问一个共享的可变变量时,为什么需要所有的线程由同一个锁同步?为了保证一个线程对数据的写入,其他线程都可见。

因此说,锁不仅仅关于同步于互斥,也关于内存可见性。

 

Volatile变量

弱同步方式:Volatile变量:确保对一个变量的更新以可预见的方式告知其他线程。

当一个域声明为Volatile类型后,编译器与运行时会监事这个变量,他是共享的,且对他的操作不会与其他的内存操作一起被重排序。

Volatile变量不会缓存在寄存器或缓存在对其他处理器隐藏的地方。

读取一个Volatile变量的操作不会加锁,不会引起执行线程的阻塞————是一种轻量级同步机制。

因此:加锁可以保证可见性与原子性;但Volatile变量只能保证可见性。

 

使用Volatile变量的标准:

写入变量时并不依赖变量的当前值,或者能确保只有单一的线程修改变量的值;

变量不需要与其他的状态变量共同参与不变约束;

访问变量时,没有其他的原因需要加锁

 

发布和逸出

发布一个对象的意思是它能被当前范围之外的代码使用;

一个对象在尚未准备好时就发布——逸出

 

线程封闭:不共享数据,如应用池化的JDBCConnection对象

 

Ad-hoc线程限制

指的是维护线程限制性的任务全部落在实现上容易出错

 

栈限制

线程限制的一种,在栈限制中,只能通过本地变量才能触及对象

 

ThreadLocal

允许你将每个线程与持有数值的对象关联在一起,并提供了get/set访问器。为每个使用它的线程维护一份单独的拷贝。因此get总是返回当前线程通过set设置最新的值。

 

不可变性:为了满足同步的需要,另一种方法是使用不可变对象。

 

 

 

Java并发编程学习笔记(1)

  • 0

    开心

    开心

  • 0

    板砖

    板砖

  • 0

    感动

    感动

  • 0

    有用

    有用

  • 0

    疑问

    疑问

  • 0

    难过

    难过

  • 0

    无聊

    无聊

  • 0

    震惊

    震惊

编辑推荐
关键字: 原子操作:原子为不可再分操作。 Violation :可见关键字。 Synchronized:内部隐示锁 Ree
为啥需要并发: 个人英雄主义,单人独写xx软件的传奇,回味孤独英雄的寂寞。 系统运行也不是单个计
关键字: 原子操作:原子为不可再分操作。 Violation :可见关键字。 Synchronized:内部隐示锁 Ree
并发编程在编写高性能, 可伸缩应用的时候经常用到的一项技术, 也是相对来说比较高级的一项技术, 是
并发编程在编写高性能, 可伸缩应用的时候经常用到的一项技术, 也是相对来说比较高级的一项技术, 是
并发编程在编写高性能, 可伸缩应用的时候经常用到的一项技术, 也是相对来说比较高级的一项技术, 是
CLH算法实现 CLH队列中的结点QNode中含有一个locked字段,该字段若为true表示该线程需要获取锁,且
NUMA与SMP SMP(Symmetric Multi-Processor),即对称多处理器结构,指服务器中多个CPU对称工作,每个
【转】http://blog.csdn.net/aesop_wubo/article/details/7533186 NUMA与SMP SMP(Symmetric Multi-P
(非原创) NUMA与SMP SMP(Symmetric Multi-Processor),即对称多处理器结构,指服务器中多个CPU对
版权所有 IT知识库 CopyRight © 2009-2015 IT知识库 IT610.com , All Rights Reserved. 京ICP备09083238号