《JAVA多线程编程核心技术》 笔记:第二章:对象及变量的并发访问
1、安全的变量和不安全的变量
2、脏读的理解
3、锁重入:
4、锁释放
5、死循环:
二、synchronized 的理解:
三、synchronized 同步方法
3.1 同步方法不具有继承性。
3.2 同步方法的弊端:
四、synchronized 同步代码块
4.1 synchronized(this)同步代码块
4.1.1 实现:
4.1.2 注意:
4.2 synchronized(x):将任意对象作为对象监视器:
4.3 synchronized、synchronized(this)和synchronized(非 this 对象)的对比
4.3.1 区别
4.3.2 细化验证3个结论:
4.4 静态同步synchronized方法和synchronized(class)代码块
4.4.1 用到static 静态方法非static 静态方法上的区别:
4.4.2 Class锁
4.4.3 synchronized(class)代码块和synchronized static 方法的相同点:
五、volatile关键字的使用
5.2、synchronized 和 volatile 的比较(可见性和原子性):
六、其他注意
6.1 String对象作为锁的注意事项
6.2 内部类和静态内部类的实例化的两种不同语法:
6.3 锁对象的改变
6.4 读写操作和原子类说明:
七、END!
一、基本概念
1、安全的变量和不安全的变量
1.1 安全的:
- 方法内的变量为线程安全。因为方法内部变量私有。
为什么?(局部变量存储在线程自己的栈中。也就是说,局部变量永远也不会被多个线程共享。参考:线程安全与共享资源 | 并发编程网 – ifeve.com http://ifeve.com/thread-safety/) - 多个对象多个锁:即synchronized 获取的是对象锁。例子中是因为a在休眠,a和b持有的是不同的对象锁,互不影响。所以b自己先执行完了。对比之前的例子:a和b用的是同一个对象,即同一个锁,所以必须一个先执行完,才能执行另一个。
1.2 不安全的
实例变量(即对象内)非线程安全。可能会被覆盖。
2、脏读的理解
可参考第3点的总结。
3、锁重入:
- 自己可以再次获取自己的内部锁。如果没有锁重入,就会造成死锁。
- 锁重入支持父子继承:即子类可以调用父类的同步方法(synchronized )。实际可这么理解:父类的方法实际就是子类的方法,子类调用的还是自己的同步方法(只是书写方式比较简单)。自己对自己锁重入完全没问题。
4、锁释放
出现异常后,锁会自动释放。
5、死循环:
- 只有一个线程,如果遇到死循环,就会一直死下去,无法改变;
- 如果两个线程可以控制同样的变量,那么程序的执行就可以被改变了。
二、synchronized 的理解:
- synchronized 获取的是对象锁(不同对象不同锁,同一对象才是一个锁)。
- synchronized 声明的方法一定排队运行。另外,只有共享资源才需要同步,非共享资源根本没有同步的必要。
- 对于 synchronized 方法和 非 synchronized 方法
- 当线程A持有该对象object的Lock锁时,线程B可以异步访问对象object中的非synchronized 方法;
- 当线程A持有该对象object的Lock锁时,线程B必须同步访问对象object中的synchronized 方法;
- 当线程A持有该对象object的Lock锁时,线程B可以异步访问对象object中的非synchronized 方法;
- 当线程A持有该对象object的Lock锁时,线程B必须同步访问对象object中的synchronized 方法;
即
- 虽然synchronized 获取的是对象锁,锁只对对象中标有 synchronized 的所有代码其作用,保证其线程安全。对其他代码不保证线程安全,如果其他代码线程不安全,可能会出现脏读。
- 只有线程获取到锁之后,才能对 synchronized 标记的代码进行操作。
三、synchronized 同步方法
3.1 同步方法不具有继承性。
即子类有一个和父类同名的方法:父类中的方法有synchronized ,子类中的方法没有synchronized ,那么子类中的方法不是同步的。这个也很好理解,因为子类覆写同名方法,相当于覆盖了父类的方法,自己没写自然没有。
3.2 同步方法的弊端:
耗时较长,因为当一个线程持有锁时,其他线程只能等待。
四、synchronized 同步代码块
4.1 synchronized(this)同步代码块
4.1.1 实现:
synchronized(this){
//相关代码
}
4.1.2 注意:
synchronized(this){
//相关代码
}
当一个线程访问object的一个synchronized (this)时,其他线程对同一个object中所有其他synchronized (this)同步代码块的访问将被阻塞,这说明synchronized 使用的“对象监视器”是一个。
可以这么理解:
对于 synchronized 锁的是一个对象,那么如果线程要执行相关synchronized 代码,都必须先得到对应的对象锁。不管synchronized 限制的是方法还是代码块。
4.2 synchronized(x):将任意对象作为对象监视器:
具体理解看原文吧,没什么好理解的。
4.3 synchronized、synchronized(this)和synchronized(非 this 对象)的对比
4.3.1 区别
- synchronized同步方法(获取的是this的对象锁)
- 对其他synchronized 同步方法或synchronized(this)同步代码块调用呈阻塞状态;
- 同一时间只有一个线程可以执行synchronized同步方法中的代码;
- synchronized(this)同步代码块(获取的是this的对象锁)
- 对其他synchronized 同步方法或synchronized(this)同步代码块调用呈阻塞状态;
- 同一时间只有一个线程可以执行synchronized(this)同步代码块中的代码;
- synchronized(非 this 对象)同步代码块(获取的是非 this 对象的对象锁)
- 持有“对象监视器”为同一个对象(即该非 this 对象的对象锁)的前提下:同一时间只有一个线程可以执行synchronized((非 this 对象)同步代码块中的代码;
总结:
this的对象锁和非 this 对象的对象锁不是同一个锁,所以无法保证线程安全。
- 如果非 this 对象表明的是同一个锁(即this锁):那么和之前synchronized没有区别
- 如果非 this 对象表明的不是同一个锁(每个线程自己的遍历):那么就是异步,会线程不安全。
4.3.2 细化验证3个结论:
- 当多个线程同时执行synchronized(x){}同步代码块时呈同步效果;
- 当其他线程执行执行x对象中synchronized同步方法时呈同步效果;
- 当其他线程执行执行x对象方面里面的synchronized(this)代码块时呈同步效果;
总结:上述3点完全无问题,线程安全的意义就是:同一时刻只能有一个线程获取该对象的对象锁,只要对象是同一个,那么对象锁就是同一个。那么肯定会保证同步效果。
4.4 静态同步synchronized方法和synchronized(class)代码块
4.4.1 用到static 静态方法非static 静态方法上的区别:
- synchronized使用到static 静态方法上,那么是对当前的*.java文件对应的Class类进行持锁(即Class锁)。
- synchronized使用到非static 静态方法上,是给对象加锁。
4.4.2 Class锁
Class锁对类的所有对象实例起作用。它是在对象上一层级的一个锁。
如果有一个Class锁,该Class锁有N个对象,两N个对象由N个线程分别执行,对于synchronized(class)代码块依旧是同步访问。
4.4.3 synchronized(class)代码块和synchronized static 方法的相同点:
实际作用一致。
五、volatile关键字的使用
## 5.1、关键字volatile的作用
5.1.1 作用:
强制从公共堆栈中取得变量的值,而不是从线程私有数据栈中取得变量的值。
5.1.2 作用的理解:为什么会用这种作用?
一个对象同时传给两个线程,看着是一个对象,但实际上,每个线程都保存有自己的一份数据。各个线程对数据的更改都是基于自己的副本进行操作。
不会立即将改变传递到公有变量中,所以可能会导致多个线程无法控制线程同步的情况。
5.1.3 注意代码中的例子:
两个例子,一个是extends Thread,一个是implements Runnable,这两种方式有什么不一样么?
在测试中:
implements Runnable 的对象中的变量,好像就是在公用堆栈中,所以更改可以立即生效。
但是: extends Thread 好像是在自己的私有堆栈中,只有使用 volatile 才会使其生效。
所以,建议多使用implements
- 非多继承的情况下:implements和extends 没区别;
- 多继承情况下:使用implements,防止出错。
5.1.4 例子总结
64位-server模式:启动线程RunThread时,设置isRunning = true,存在于公共堆栈,以及线程的私有堆栈中;
64位-server模式为了线程运行效率,线程一直从私有堆栈中取得isRunning = true。
而:thread.setRunning(false); 更新的是公共堆栈中的isRunning = false。所以代码一直是死循环。
主要原因:公用堆栈中的值和私有堆栈中的值不同步;
解决方法,在isRunning 前加上volatile关键字(强制从公共堆栈中取值)
5.2、synchronized 和 volatile 的比较(可见性和原子性):
volatile 关键字 (解决变量在多个线程之间的可见性) |
synchronized 关键字 (解决多个线程之间的访问资源的同步性) |
---|---|
线程同步的轻量实现,比 synchronized 好; | 比volatile差一点 |
只能修饰变量 | 可修饰方法、代码块和变量 |
不会阻塞 | 会阻塞 |
保证数据的可见性(读阶段),不保证原子性(写阶段) (即多个线程同时更改同一变量,就会有问题); |
保证原子性(写阶段),间接保证可见性(读阶段) (因为会将私有内存和公有内存中中的数据同步); |
其他说明:
synchronized 代码块有volatile 同步的功能:
- synchronized可以使多个线程访问同一个资源具有同步性(即同一时刻,只有一个线程可以执行synchronized保护的代码;);
- synchronized还能将线程工作内存中的私有变量和公共内存中的变量同步(可以解决一个线程看到对象处于不一致的状态,还可以保证进入同步方法或同步代码块的每个线程,都看到由同一个锁保护之前所有的修改效果;)
六、其他注意
6.1 String对象作为锁的注意事项
注意:如果使用String对象作为锁,需注意当String一致时,他们其实是同一个对象,不像对象那样,即使里面的String相同,也不是同一个对象。
"aa" == "aa" //true
new String("a") == new String("a") //false
如果不注意可能会导致锁的有问题。
6.2 内部类和静态内部类的实例化的两种不同语法:
非静态内部类: 外部类.new 内部类名
静态内部类: 直接 new 类名即可,和普通的类新建对象没有什么区别。
6.3 锁对象的改变
这个例子说明了两个知识点:
- 锁的争抢只在线程开始执行的一瞬间,后续对于该锁的争抢是不会变的。即使在代码中动态改变了锁对应的对象。只要代码没有执行完,那么所有相关的锁都是一样的。
对象不变,即使对象的属性被改变,那么对该对象持有的锁并不会变。
6.4 读写操作和原子类说明:
1、读写操作一般分为3阶段:读→用→写。读和写各为原子操作。但读写在一起并不为原子操作。
2、可以使用原子类进行 i++操作:
注意:原子类本身操作安全,但是如果代码执行顺序不安全,从线程整体来看,还是不安全的。
七、END!
《JAVA多线程编程核心技术》 笔记:第二章:对象及变量的并发访问的更多相关文章
- Java多线程编程核心技术-第2章-对象及变量的并发访问-读书笔记
第 2 章 对象及变量的并发访问 本章主要内容 synchronized 对象监视器为 Object 时的使用. synchronized 对象监视器为 Class 时的使用. 非线程安全是如何出现的 ...
- java多线程编程核心技术(二)--对象及变量的并发访问
1.方法内部的私有变量是线程安全的,实例变量是线程不安全的. 2.A线程先持有object对象的lock锁,B线程可以以异步的方式调用object对象中的非synchronized类型的方法. 3.A ...
- Java多线程编程核心技术,第二章,对象和变量并发访问
1,方法内部变量是线程安全的 2,实例变量非线程安全 3,synchronized是锁对象不是锁方法(锁对象是可以访问非synchronized方法,不可访问同个和其他synchronized方法 4 ...
- Java多线程编程核心技术-第1章-Java多线程技能-读书笔记
第 1 章 Java 多线程技能 本章主要内容 线程的启动 如何使线程暂停 如何使线程停止 线程的优先级 线程安全相关的问题 1.1 进程和多线程的概念及线程的优点 进程是操作系统结构的基础:是一次程 ...
- Java多线程编程核心技术-第5章-定时器 Timer-读书笔记
第 5 章 定时器 Timer 定时 / 计划功能在移动开发领域使用较多,比如 Android 技术.定时计划任务功能在 Java 中主要使用的就是 Timer 对象,他在内部使用多线程的方式进行处理 ...
- Java多线程编程核心技术-第4章-Lock的使用-读书笔记
第 4 章 Lock 的使用 本章主要内容 ReentrantLocal 类的使用. ReentrantReadWriteLock 类的使用. 4.1 使用 ReentrantLock 类 在 Jav ...
- java多线程编程核心技术-笔记
一.第一章 1.自定义线程类中实例变量针对其他线程有共享和不共享之分,自定义线程中的变量,如果是继承自thread类,则每个线程中的示例变量的更改,不影响其他线程2.当多个线程去访问一个局部变量是会产 ...
- Java多线程编程核心技术-第7章-拾遗增补-读书笔记
第 7 章 拾遗增补 本章主要内容 线程组的使用. 如何切换线程状态. SimpleDataFormat 类与多线程的解决办法. 如何处理线程的异常. 7.1 线程的状态 线程对象在不同的运行时期有不 ...
- Java多线程编程核心技术-第6章-单例模式与多线程-读书笔记
第 6 章 单例模式与多线程 本章主要内容 如何使单例模式遇到多线程是安全的.正确的. 6.1 立即加载 / “饿汉模式” 什么是立即加载?立即加载就是使用类的时候已经将对象创建完毕,常见的实现办法就 ...
- Java多线程编程核心技术-第3章-线程间通信-读书笔记
第 3 章 线程间通信 线程是操作系统中独立的个体,但这些个体如果不经过特殊的处理就不能成为一个整体.线程间的通信就是成为整体的必用方案之一,可以说,使线程间进行通信后,系统之间的交互性会更强大,在大 ...
随机推荐
- List分组迭代器 C#--深入理解类型
List分组迭代器 说明: 针对长度较大的List对象,可以分组批量进行处理, 如:长度为1000的List对象,可分为10组,每组100条,对数据进行业务逻辑处理... Source /**** ...
- C# 取字符串中间文本 取字符串左边 取字符串右边
好像是第二种效率高一点,取str字符串中123左边的所有字符:第一种Between(str,"","123"),而第二种是Between(str,null,&q ...
- win8安装Visual C++ 2015 build tools闪退解决办法
win8安装Visual C++ 2015 build tools闪退解决办法 安装Visual Studio 2015闪退问题也同样应用此解决办法. 1.控制面板——添加删除程序——启动关闭wind ...
- macbook使用“终端”远程登录linux主机
登录mac系统后,依次打开顶部菜单,“前往” -> “应用程序” -> “实用工具” -> “终端”,如下图: 在打开的终端页面,输入如下代码: ssh user@hostnam ...
- redis数据类型List的安全队列和不安全队列
在学习RPOPLPUSH命令的时候,官方文档中有提到安全队列和不安全的队列,一开始没有看懂,现在理解了做个笔记. 一般情况下,我们可以借助List来实现消息队列,比如一个客户端通过命令LPUSH(BL ...
- Linq Mysql GroupBy语句的问题处理
语句如下: var resumeList = db.ChannelResume.Where(model); var groupValues = resumeList.GroupBy(t => n ...
- 微信抢红包微信 PHP代码实现
header("Content-Type: text/html;charset=utf-8");//输出不乱码,你懂的 $total=10;//红包总额 $num=8;// 分成8 ...
- 腾讯课堂1:使用Jmeter内置的录制功能进行录制
1.设置http代理服务器 打开火狐——点击选项——高级——网络——设置 设置完成点击确定 2.查看端口是否被占用的命令 netstat -ano 3.排除模式 .*\.gif .*\.css .* ...
- 如何将HTML页面的标题设置为“数字天堂”。
如何将HTML页面的标题设置为“数字天堂”. 解答: <html> <head><title>数字天堂</title></head> < ...
- 利用JQuery jsonp实现Ajax跨域请求 .Net 的*.handler 和 WebService,返回json数据
1:跨域请求handler一般处理程序 using System; using System.Collections.Generic; using System.Web; using System.W ...
第 2 章 对象及变量的并发访问 本章主要内容 synchronized 对象监视器为 Object 时的使用. synchronized 对象监视器为 Class 时的使用. 非线程安全是如何出现的 ...
1.方法内部的私有变量是线程安全的,实例变量是线程不安全的. 2.A线程先持有object对象的lock锁,B线程可以以异步的方式调用object对象中的非synchronized类型的方法. 3.A ...
1,方法内部变量是线程安全的 2,实例变量非线程安全 3,synchronized是锁对象不是锁方法(锁对象是可以访问非synchronized方法,不可访问同个和其他synchronized方法 4 ...
第 1 章 Java 多线程技能 本章主要内容 线程的启动 如何使线程暂停 如何使线程停止 线程的优先级 线程安全相关的问题 1.1 进程和多线程的概念及线程的优点 进程是操作系统结构的基础:是一次程 ...
第 5 章 定时器 Timer 定时 / 计划功能在移动开发领域使用较多,比如 Android 技术.定时计划任务功能在 Java 中主要使用的就是 Timer 对象,他在内部使用多线程的方式进行处理 ...
第 4 章 Lock 的使用 本章主要内容 ReentrantLocal 类的使用. ReentrantReadWriteLock 类的使用. 4.1 使用 ReentrantLock 类 在 Jav ...
一.第一章 1.自定义线程类中实例变量针对其他线程有共享和不共享之分,自定义线程中的变量,如果是继承自thread类,则每个线程中的示例变量的更改,不影响其他线程2.当多个线程去访问一个局部变量是会产 ...
第 7 章 拾遗增补 本章主要内容 线程组的使用. 如何切换线程状态. SimpleDataFormat 类与多线程的解决办法. 如何处理线程的异常. 7.1 线程的状态 线程对象在不同的运行时期有不 ...
第 6 章 单例模式与多线程 本章主要内容 如何使单例模式遇到多线程是安全的.正确的. 6.1 立即加载 / “饿汉模式” 什么是立即加载?立即加载就是使用类的时候已经将对象创建完毕,常见的实现办法就 ...
第 3 章 线程间通信 线程是操作系统中独立的个体,但这些个体如果不经过特殊的处理就不能成为一个整体.线程间的通信就是成为整体的必用方案之一,可以说,使线程间进行通信后,系统之间的交互性会更强大,在大 ...
List分组迭代器 说明: 针对长度较大的List对象,可以分组批量进行处理, 如:长度为1000的List对象,可分为10组,每组100条,对数据进行业务逻辑处理... Source /**** ...
好像是第二种效率高一点,取str字符串中123左边的所有字符:第一种Between(str,"","123"),而第二种是Between(str,null,&q ...
win8安装Visual C++ 2015 build tools闪退解决办法 安装Visual Studio 2015闪退问题也同样应用此解决办法. 1.控制面板——添加删除程序——启动关闭wind ...
登录mac系统后,依次打开顶部菜单,“前往” -> “应用程序” -> “实用工具” -> “终端”,如下图: 在打开的终端页面,输入如下代码: ssh user@hostnam ...
在学习RPOPLPUSH命令的时候,官方文档中有提到安全队列和不安全的队列,一开始没有看懂,现在理解了做个笔记. 一般情况下,我们可以借助List来实现消息队列,比如一个客户端通过命令LPUSH(BL ...
语句如下: var resumeList = db.ChannelResume.Where(model); var groupValues = resumeList.GroupBy(t => n ...
header("Content-Type: text/html;charset=utf-8");//输出不乱码,你懂的 $total=10;//红包总额 $num=8;// 分成8 ...
1.设置http代理服务器 打开火狐——点击选项——高级——网络——设置 设置完成点击确定 2.查看端口是否被占用的命令 netstat -ano 3.排除模式 .*\.gif .*\.css .* ...
如何将HTML页面的标题设置为“数字天堂”. 解答: <html> <head><title>数字天堂</title></head> < ...
1:跨域请求handler一般处理程序 using System; using System.Collections.Generic; using System.Web; using System.W ...