在并发环境下,解决共享资源冲突问题时,可以考虑使用锁机制。
1.对象的锁
所有对象都自动含有单一的锁。
JVM负责跟踪对象被加锁的次数。如果一个对象被解锁,其计数变为0。在任务(线程)第一次给对象加锁的时候,计数变为1。每当这个相同的任务(线程)在此对象上获得锁时,计数会递增。
只有首先获得锁的任务(线程)才能继续获取该对象上的多个锁。
每当任务离开一个synchronized方法,计数递减,当计数为0的时候,锁被完全释放,此时别的任务就可以使用此资源。
2.synchronized同步块
synchronized有两种格式:

格式1:
synchronized(任何对象){
  //访问共享变量的临界区(程序段),又称同步代码块
}
格式2:同步化方法。在方法的前面加上synchronized,如:
public synchronized void add() {
//临界区
}
共享变量所关联的对象锁是如何选择的?即
synchronized (任何对象) {
//临界区
}
  1.synchronized锁定的是一个具体对象,通常是共享变量的对象。用synchronized括起来的程序段是访问该共享变量的临界区,即synchronized代码块。由于所有锁定同一个对象的线程之间,在synchronized代码块上是互斥的,也就是说,这些线程的synchronized代码块之间是串行执行的,不再是互相交替穿插并发执行,因而保证了synchronized 代码块操作的原子性。但synchronized代码块与所有线程的非synchronized 代码块之间以及非synchronized代码块与非synchronized代码块之间都是互相交替穿插并发执行的,故synchronized代码块操作的原子性是逻辑上的,而不是物理上的不可打断。

 2.每一个Java对象都有且只有一个对象锁。任何时刻,一个对象锁只能被一个线程所拥有。若两个或多个线程锁定的不是同一个对象,则它们的synchronized代码块可以互相交替穿插并发执行。
 
3.所有的非synchronized代码块或方法,都可自由调用。如线程A获得了对象锁,调用需要该对象锁的synchronized代码块,其他线程仍然可以自由调用所有非synchronized方法和代码
 
4.若线程A获得了对象O的对象锁,调用对象O的synchronized代码块或方法,则线程A仍然可以调用其他任何需要对象O的锁的synchronized代码块或方法,这是因为线程A已经获得了对象O的对象锁了。线程A同时可以调用需要另一个对象K的锁的synchronized代码块或方法,这意味着线程A同时拥有对象O和对象K的对象锁。
 
5.只有当一个线程执行完它所调用的synchronized代码块或方法时,无论是正常执行完,还是异常抛出,该线程才会释放所获取的对象锁。synchronized并不必然地保护数据。程序员应该仔细分析,识别出程序中所有的临界区,并对这些临界区施加synchronized机制。若有一处或多处遗漏,则共享变量中数据就会产生错误
 
6.临界区中的共享变量应定义为private型。否则,其他类的方法可能直接访问和操作该共享变量,这样synchronized的保护就失去了意义。所以只能通过临界区访问共享变量。故锁定的对象通常是this,即通常格式都是:synchronized(this){…}
 
7.一定要保证,所有对共享变量的访问与操作均在synchronized代码块中进行。
 
8.通常共享变量都是实例变量。若临界区中的共享变量是一个类变量,则问题复杂化了,因为类方法与实例方法均可访问类变量。而synchronized锁定的必须是对象,不能是类。建议是若临界区中的共享变量是一个类变量,则应该用类方法来访问操作该类变量。这个类方法成为一个临界区,必须将该类方法定义为synchronized方法。所有要访问该共享类变量的实例方法,都应该调用定义为synchronized的类方法进行。若实例方法一定要想在自己的代码内部,不通过synchronized的类方法访问共享类变量,则可通过synchronized(类名.class){…来访问类锁。Java中,每一个类都有一个类对象,这个类对象实际上是java.lang.Class的一个实例对象,所谓类锁就是这个类对象的一把锁。注意类锁与这个类的实例对象的对象锁虽然都是对象锁,却是不同的两把锁。所有像synchronized(类名.class()){=同步代码块} 这样锁定类对象(注意:不是锁定类的某一个实例对象),其中的synchronized代码块,都是串行执行的,访问或使用类锁要仔细考虑和权衡
 
9.当一个线程进入死亡状态,线程拥有的所有的对象锁都被释放。
3.Lock对象锁
 

Java SE5引入了java.util.concurrent.lock类库,这是解决互斥问题的第二种机制。用ReentrantLock类创建一个Lock对象,来保护临界区。用ReentrantLock保护代码块的基本结构如下。
private Lock locker =new ReentrantLock();
locker.lock(); // 加锁
try{
}finally{
  locker.unlock(); // 解锁
  }
lock()与unlock()必须配套使用。必须确保lock()对应的unlock()一定会得到执行。因此,必须把unlock()放到finally块中,确保无论是正常执行,还是异常抛出,unlock()一定会得到执行。
 
 
synchronized和lock的区别:
 
Lock 的锁定是通过代码实现的,而 synchronized 是在 JVM 层面上实现的
synchronized 在锁定时如果方法块抛出异常,JVM 会自动将锁释放掉,不会因为出了异常没有释放锁造成线程死锁。但是 Lock 的话就享受不到 JVM 带来自动的功能,出现异常时必须在 finally 将锁释放掉,否则将会引起死锁。
 
在资源竞争不是很激烈的情况下,偶尔会有同步的情形下,synchronized是很合适的。原因在于,编译程序通常会尽可能的进行优化synchronize,另外可读性非常好,不管用没用过5.0多线程包的程序员都能理解。

ReentrantLock: 
ReentrantLock提供了多样化的同步,比如有时间限制的同步,可以被Interrupt的同步(synchronized的同步是不能Interrupt的)等。在资源竞争不激烈的情形下,性能稍微比synchronized差点点。但是当同步非常激烈的时候,synchronized的性能一下子能下降好几十倍。而ReentrantLock确还能维持常态。

Atomic: 
和上面的类似,不激烈情况下,性能比synchronized略逊,而激烈的时候,也能维持常态。激烈的时候,Atomic的性能会优于ReentrantLock一倍左右。但是其有一个缺点,就是只能同步一个值,一段代码中只能出现一个Atomic的变量,多于一个同步无效。因为他不能在多个Atomic之间同步。 

 
 

JAVA--对象锁的更多相关文章

  1. [转]Java 对象锁-synchronized()与线程的状态与生命周期

      线程的状态与生命周期 Java 对象锁-synchronized() ? 1 2 3 4 synchronized(someObject){   //对象锁 } 对象锁的使用说明: 1.对象锁的返 ...

  2. java 对象锁和类锁的区别(转)

    java 对象锁和类锁的区别   转自; ) ); ; ) ); 上述的代码,第一个方法时用了同步代码块的方式进行同步,传入的对象实例是this,表明是当前对象,当然,如果需要同步其他对象实例,也不可 ...

  3. Java对象锁和类锁全面解析(多线程synchronized关键字)

    最近工作有用到一些多线程的东西,之前吧,有用到synchronized同步块,不过是别人怎么用就跟着用,并没有搞清楚锁的概念.最近也是遇到一些问题,不搞清楚锁的概念,很容易碰壁,甚至有些时候自己连用没 ...

  4. java 对象锁学习

    机制 锁机制是用来解决多线程共享资源时产生的冲突问题的.java 为每一个对象关联一个对象锁,通常把锁分为对象锁和类锁,他们的本质都是对象锁,只不过对象锁关联的是类的 Object 对象 (java. ...

  5. paip.提升性能----java 无锁结构(CAS, Atomic, Threadlocal, volatile, 函数式编码, 不变对象)

    paip.提升性能----java 无锁结构(CAS, Atomic, Threadlocal, volatile, 函数式编码, 不变对象) 1     锁的缺点 2     CAS(Compare ...

  6. java synchronized类锁,对象锁详解(转载)

    觉得还不错 留个记录,转载自http://zhh9106.iteye.com/blog/2151791 在java编程中,经常需要用到同步,而用得最多的也许是synchronized关键字了,下面看看 ...

  7. java 哪些情况下会使对象锁释放

    Java_多线程_锁释放 问:Java多线程运行环境中,在哪些情况下会使对象锁释放?答:由于等待一个锁的线程只有在获得这把锁之后,才能恢复运行,所以让持有锁的线程在不再需要锁的时候及时释放锁是很重要的 ...

  8. Java:使用synchronized和Lock对象获取对象锁

    在并发环境下,解决共享资源冲突问题时,可以考虑使用锁机制. 1.对象的锁 所有对象都自动含有单一的锁. JVM负责跟踪对象被加锁的次数.如果一个对象被解锁,其计数变为0.在任务(线程)第一次给对象加锁 ...

  9. Java虚拟机14:Java对象大小、对象内存布局及锁状态变化

    一个对象占多少字节? 关于对象的大小,对于C/C++来说,都是有sizeof函数可以直接获取的,但是Java似乎没有这样的方法.不过还好,在JDK1.5之后引入了Instrumentation类,这个 ...

  10. Java锁Synchronized,对象锁和类锁举例

    Java的锁分为对象锁和类锁. 1. 当两个并发线程访问同一个对象object中的这个synchronized(this)同步代码块时,一个时间内针对该对象的操作只能有一个线程得到执行.另一个线程必须 ...

随机推荐

  1. 两个for循环例子

    var i,j; var a=0; // for(i=0,j=0;i<5,j<7;i++,j++){ // a=i+j; // } // alert(a) //12 for(i=0,j=0 ...

  2. PhoneGap与WAP站静态化

    最近在参与的WAP站项目,决定将所有页面都静态化处理,登录验证.价格数据等都通ajax动态的方式实现.开始这么规划的目前是为了页面提高网站加载速度及SEO,最近看到了一篇报道phonegap buil ...

  3. vs2005用正则表达式统计有效代码行数

    正则表达式:^:b*[^:b#/]+.*$ 需要注意:#开头和/开头或者空行都不计入代码量. 如果需要只统计代码文件的代码量,可以按住Ctrl+Shift+F之后选择查找文件的类型. Form:htt ...

  4. SimpleXML解析xml文件

    SimpleXML 扩展提供了一种获取 XML 元素的名称和文本的简单方式. 与 DOM 或 Expat 解析器相比,SimpleXML 仅仅用几行代码就可以从 XML 元素中读取文本数据. Simp ...

  5. MySQL数据库添加一个字段

    MySQL数据库添加一个字段 1.添加一个字段 alter table tableName add 列名  数据类型; 2.添加一个字段设置默认值 alter table tableName add ...

  6. 面试题: generate an equation, by inserting operator add ("+") and minus ("-") among the array to make equationExpression == 0

    package com.Amazon.interview; /** * @Author: weblee * @Email: likaiweb@163.com * @Blog: http://www.c ...

  7. loadView 与 ViewDidLoad

    每个ios开发者对loadView和viewDidLoad肯定都很熟悉,虽然这两个函数使用上真的是非常简单,但是和类似的initWithNibName/awakeFromNib/initWithCod ...

  8. 7个热门开源PHP框架

    PHP(Hypertext Preprocessor)是一种通用开源脚本语言.语法吸收了C语言.Java和Perl的特点.虽然有很多其它可供选择的Web开发语言,像:ASP 和Ruby,但是PHP是目 ...

  9. 最浅显、易懂的Linux 硬链接与软链接的理解

    正文: Linux上的文件可以这么理解:文件-->文件名.文件是一个Object,也就是磁盘上的二进制数据.一个文件可以有多个文件名,平时我们都是通过文件名访问文件Object. 这样,硬链接可 ...

  10. matlab中 hold on 与hold off的用法

    matlab中 hold on 与hold off的用法 hold on 是当前轴及图形保持而不被刷新,准备接受此后将绘制 hold off 使当前轴及图形不在具备被刷新的性质 hold on 和ho ...