使用对象锁与多线程访问资源控制
2013-08-15 16:55
309 查看
1、线程持有所和资源访问
上述的methodA中,持有了RA的锁,这并不代表RA不能被其他线程所访问。RA一样是一个普通的资源,这个资源可以被任何资源访问。那么对RA加锁有什么用呢?
多线程同步块的锁,是用于限制对线程对该块的并发执行,只有持有该锁的线程,才有执行该代码块的权利。也可以说,这个锁时一个入门的钥匙,你需要想JVM获取到这个钥匙,你才能进来这个代码快的门。当执行完毕之后,会将钥匙归还给JVM。此时jvm才能将钥匙给另外一个人(线程),否则那个人会一直等待你吧钥匙归还。
但是RA作为一个资源,在不同的代码快中使用它是完全没有限制的,只要不是同一个代码块中,就可以多线程访问。所以methodB和methodA都会并发访问资源RA。
2、使用对象锁
1中描述的例子,RA和RB的定义分别如下:
private Boolean RA = false ;
private Boolean RB = false ;
当程序并发访问methodA和methodB时,你会发现,methodB需要等待methodA执行完之后才能执行。为什么会这样?他们明明是不同的锁??
问题出现在变量的赋值上。Boolean虽然是对象,但是在初始化时是使用基本类型的值false赋值的,false和true作为基本变量值,是存储在jvm的栈内存中,这里先说说栈:
栈 的优势
存取速度比堆要快,仅次于寄存器,栈数据可以共享。但缺点是,存在栈中的数据大小与生存期必须是确定的,缺乏灵活性。栈中主要存放一些基本类型的变量( int, short, long, byte, float, double, boolean, char )和对象引用。
栈有一个很重要的特殊性,就是存在栈中的数据可以共享。 假设我们同时定义:
int a = 3;
int b = 3 ;
编译器先处理 int a = 3 ;首先它会在栈中创建一个变量为 a 的引用,然后查找栈中是否有 3 这个值,如果没找到,就将 3 存放进来,然后将 a 指向 3 。接着处理 int b = 3 ;在创建完 b 的引用变量后,因为在栈中已经有 3 这个值,便将 b 直接指向 3 。这样,就出现了 a 与 b 同时均指向 3 的情况。这时,如果再令 a=4 ;那么编译器会重新搜索栈中是否有 4 值,如果没有,则将 4 存放进来,并令 a 指向 4 ;如果已经有了,则直接将 a 指向这个地址。因此 a 值的改变不会影响到 b 的值。要注意这种数据的共享与两个对象的引用同时指向一个对象的这种共享是不同的,因为这种情况 a 的修改并不会影响到 b, 它是由编译器完成的,它有利于节省空间。而一个对象引用变量修改了这个对象的内部状态,会影响到另一个对象引用变量。
从上述的描述中,我们可以知道,RA和RB其实都是指向栈内存中的false对象。如果将RB初始化为true,那么就可以对methodA和methodB进行并发访问。但是其实这样是很危险的,因为false有可能也被其他线程访问。那么就会出现等待了。
所以不要使用基本类型作为线程锁。
引申:
下面主要介绍 JAVA 中的堆、 栈 和 常量池 :
1. 寄存器
最快的存储区, 由编译器根据需求进行分配,我们在程序中无法控制。
2. 栈
存放基本类型的变量数据和对象的引用,但对象本身不存放在栈中,而是存放在堆(new 出来的对象)或者常量池中(字符串常量对象存放在常量池中。)
3. 堆
存放所有new出来的对象。
4. 静态域
存放静态成员(static定义的)
5. 常量池
存放字符串常量和基本类型常量(public static final)。
6. 非RAM存储
硬盘等永久存储空间
这里我们主要关心栈,堆和常量池,对于栈和常量池中的对象可以共享,对于堆中的对象不可以共享。栈中的数据大小和生命周期是可以确定的,当没有引用指向数据时,这个数据就会消失。堆中的对象的由垃圾回收器负责回收,因此大小和生命周期不需要确定,具有很大的灵活性。
对于字符串:其对象的引用都是存储在栈中的,如果是编译期已经创建好(直接用双引号定义的)的就存储在常量池中,如果是运行期(new出来的)才能确定的就存储在堆中。对于equals相等的字符串,在常量池中永远只有一份,在堆中有多份。
参考资料:/article/5654522.html
public void methodA () throws InterruptedException{ synchronized (RA) { RC = true ; } } public void methodB() throws InterruptedException{ synchronized (RB) { RA = true ; } }
上述的methodA中,持有了RA的锁,这并不代表RA不能被其他线程所访问。RA一样是一个普通的资源,这个资源可以被任何资源访问。那么对RA加锁有什么用呢?
多线程同步块的锁,是用于限制对线程对该块的并发执行,只有持有该锁的线程,才有执行该代码块的权利。也可以说,这个锁时一个入门的钥匙,你需要想JVM获取到这个钥匙,你才能进来这个代码快的门。当执行完毕之后,会将钥匙归还给JVM。此时jvm才能将钥匙给另外一个人(线程),否则那个人会一直等待你吧钥匙归还。
但是RA作为一个资源,在不同的代码快中使用它是完全没有限制的,只要不是同一个代码块中,就可以多线程访问。所以methodB和methodA都会并发访问资源RA。
2、使用对象锁
1中描述的例子,RA和RB的定义分别如下:
private Boolean RA = false ;
private Boolean RB = false ;
当程序并发访问methodA和methodB时,你会发现,methodB需要等待methodA执行完之后才能执行。为什么会这样?他们明明是不同的锁??
问题出现在变量的赋值上。Boolean虽然是对象,但是在初始化时是使用基本类型的值false赋值的,false和true作为基本变量值,是存储在jvm的栈内存中,这里先说说栈:
栈 的优势
存取速度比堆要快,仅次于寄存器,栈数据可以共享。但缺点是,存在栈中的数据大小与生存期必须是确定的,缺乏灵活性。栈中主要存放一些基本类型的变量( int, short, long, byte, float, double, boolean, char )和对象引用。
栈有一个很重要的特殊性,就是存在栈中的数据可以共享。 假设我们同时定义:
int a = 3;
int b = 3 ;
编译器先处理 int a = 3 ;首先它会在栈中创建一个变量为 a 的引用,然后查找栈中是否有 3 这个值,如果没找到,就将 3 存放进来,然后将 a 指向 3 。接着处理 int b = 3 ;在创建完 b 的引用变量后,因为在栈中已经有 3 这个值,便将 b 直接指向 3 。这样,就出现了 a 与 b 同时均指向 3 的情况。这时,如果再令 a=4 ;那么编译器会重新搜索栈中是否有 4 值,如果没有,则将 4 存放进来,并令 a 指向 4 ;如果已经有了,则直接将 a 指向这个地址。因此 a 值的改变不会影响到 b 的值。要注意这种数据的共享与两个对象的引用同时指向一个对象的这种共享是不同的,因为这种情况 a 的修改并不会影响到 b, 它是由编译器完成的,它有利于节省空间。而一个对象引用变量修改了这个对象的内部状态,会影响到另一个对象引用变量。
从上述的描述中,我们可以知道,RA和RB其实都是指向栈内存中的false对象。如果将RB初始化为true,那么就可以对methodA和methodB进行并发访问。但是其实这样是很危险的,因为false有可能也被其他线程访问。那么就会出现等待了。
所以不要使用基本类型作为线程锁。
引申:
下面主要介绍 JAVA 中的堆、 栈 和 常量池 :
1. 寄存器
最快的存储区, 由编译器根据需求进行分配,我们在程序中无法控制。
2. 栈
存放基本类型的变量数据和对象的引用,但对象本身不存放在栈中,而是存放在堆(new 出来的对象)或者常量池中(字符串常量对象存放在常量池中。)
3. 堆
存放所有new出来的对象。
4. 静态域
存放静态成员(static定义的)
5. 常量池
存放字符串常量和基本类型常量(public static final)。
6. 非RAM存储
硬盘等永久存储空间
这里我们主要关心栈,堆和常量池,对于栈和常量池中的对象可以共享,对于堆中的对象不可以共享。栈中的数据大小和生命周期是可以确定的,当没有引用指向数据时,这个数据就会消失。堆中的对象的由垃圾回收器负责回收,因此大小和生命周期不需要确定,具有很大的灵活性。
对于字符串:其对象的引用都是存储在栈中的,如果是编译期已经创建好(直接用双引号定义的)的就存储在常量池中,如果是运行期(new出来的)才能确定的就存储在堆中。对于equals相等的字符串,在常量池中永远只有一份,在堆中有多份。
参考资料:/article/5654522.html
相关文章推荐
- 使用临界区CRITICAL_SECTION结构对象保护多线程互斥地访问共享资源
- 多线程访问 资源的安全控制
- 使用BackGroundWorker在多线程中访问Winform控件,当不是创建这个控件的线程访问控件时,把线程调整到是创建这个控件的线程去控制。,代码为红色的
- 使用springMVC实现基于资源的访问控制
- Java多线程~~~使用信号量来控制资源获取
- 【Java开发】使用Semaphore控制资源访问并发量
- 多线程访问 资源的安全控制
- 在struts框架中使用Action作为资源的访问控制设计考虑
- Java中的Semaphore--用于多线程中控制资源并发访问的线程数
- 多线程Demo-Semaphore 控制同时访问资源的线程个数
- C++使用临界区来控制多线程访问同一个变量
- 【Java多线程】使用Semaphore限制资源访问的线程数
- Semaphor控制资源访问的使用方法
- 使用JS闭包控制对象属性访问范围
- Semaphor控制资源访问的使用方法
- 多线程访问 资源的安全控制
- 应用程序中的所有线程都可以访问方法中的公用字段。要同步对公用字段的访问,您可以使用属性替代字段,并使用 ReaderWriterLock 对象控制访问。为此,请按照下列步骤操作:
- 关于Java.net.URL对象使用Proxy访问Internet资源
- VC使用ADO对象控制ACCESS数据库的访问
- 使用管道流和多线程完成以下任务要求: 一个线程对象t1 会从控制台中不停的读取信息,读到之后把数据交给管道输出流,把数据写到管道里面 ,另一个线程对象t2 不停的使用管道输入流从管道