java synchronized与lock区别

转自:http://blog.youkuaiyun.com/liaomin416100569/archive/2010/01/11/5172652.aspx

synchronized 修饰方法时 表示同一个对象在不同的线程中 表现为同步队列

如果实例化不同的对象 那么synchronized就不会出现同步效果了

1.对象的锁
所有对象都自动含有单一的锁。
JVM负责跟踪对象被加锁的次数。如果一个对象被解锁,其计数变为0。在任务(线程)第一次给对象加锁的时候,计数变为1。每当这个相同的任务(线程)在此对象上获得锁时,计数会递增。
只有首先获得锁的任务(线程)才能继续获取该对象上的多个锁。
每当任务离开一个synchronized方法,计数递减,当计数为0的时候,锁被完全释放,此时别的任务就可以使用此资源。
2.synchronized同步块
2.1同步到单一对象锁
当使用同步块时,如果方法下的同步块都同步到一个对象上的锁,则所有的任务(线程)只能互斥的进入这些同步块。
Resource1.java演示了三个线程(包括main线程)试图进入某个类的三个不同的方法的同步块中,虽然这些同步块处在不同的方法中,但由于是同步到同一个对象(当前对象 synchronized (this)),所以对它们的方法依然是互斥的。
比如

Class Test

{

    public static User user=null;

      Public synchronized void add(User u)

{

     user=u;

     Dao.save(user)

}

}

 

如果在线程1中 Test test=new Test();

User u=new User();

u.setUserName(“liaomin”);

u.setUserPassword(“liaomin”);

                Test.add(u);

如果在线程2中 Test tes1t=new Test();

User u1=new User();

u1.setUserName(“huqun”);

u1.setUserPassword(“huqun”);

 

                Tes1t.add(u1);

那么 现在线程1 和线程2同时启动 如果对象new的不是同一个Test

那么出现线程交叉的话 那么插入数据库中的数据就是相同的

因为你的user变量时静态的   你给他赋值第一次 假如还没有save的时候

另外一个线程改变了user的值 那么第一个线程插入时也就是第二次赋予的值了

 

所以要实现同步 那么可以改方法为静态的就能达到同步的效果了

修改如下

Public static synchronized void add(User u)

{

     user=u;

     Dao.save(user)

}

修改为static的方法是存在于堆中

是全局方法 针对于所有实例化与未 实例化的对象只存在一个 所以会出现同步队列

 

 

当然不用static 也可以 那就用lock

Class Test

{

public static User user=null;

Lock lock=new ReentrantLock();

 

      Public void add(User u)

{

lock.lock();

     user=u;

     Dao.save(user);

lock.unlock();

}

}

这样无论你new多少个对象都会是线程同步的

相当于

Public static synchronized void add(User u)

{

     user=u;

     Dao.save(user)

}

 

同时 lock性能上高于synchronized

只是lock需要手动关闭

 

ps:

主要相同点:lock能完成synchronized所实现的所有功能
主要不同点:lock有比synchronized更精确的线程语义和更好的性能.synchronized会自动释放锁,而Lock一定要求程序员手工释放,并且必须在finally从句中释放.

### synchronizedLock区别对比 #### 实现方式 `synchronized` 是 Java 内置的关键字,由 JVM 层面实现。它可以用于方法或代码块: ```java public synchronized void method() { // 同步方法体 } ``` 或者 ```java public void method() { synchronized(this) { // 同步代码块 } } ``` 而 `Lock` 是一个接口,位于 `java.util.concurrent.locks` 包中,需要通过编程方式手动获取释放锁[^3]。 #### 获取释放锁 使用 `synchronized` 时,锁的获取释放是自动进行的,当线程进入同步代码块或方法时会自动获取锁,退出时会自动释放锁。这种方式简化了开发人员的工作,但也可能导致一些问题,例如死锁[^2]。 对于 `Lock` 接口,锁的获取释放必须显式地调用 `lock()` `unlock()` 方法来完成。这种灵活性允许更复杂的锁定模式,但也增加了出错的可能性。例如: ```java Lock lock = new ReentrantLock(); lock.lock(); try { // 执行临界区代码 } finally { lock.unlock(); // 必须在finally块中释放锁以确保异常情况下也能释放锁 } ``` #### 锁类型 默认情况下,`synchronized` 提供的是非公平锁,即多个线程竞争锁的时候,JVM 不保证哪个线程会获得锁。相比之下,`ReentrantLock` 允许选择是否为公平锁(通过构造函数参数指定)。如果希望线程按照请求顺序获得锁,则可以选择公平锁[^2]。 #### 可中断性 当线程试图获取由 `synchronized` 保护的资源时,如果该资源已被其他线程占用,那么这个线程将被阻塞直到锁可用。在此期间,线程不能响应中断。相反,`Lock` 接口提供了 `lockInterruptibly()` 方法,使得线程可以在等待锁的同时响应中断,这有助于避免死锁情况的发生[^4]。 #### 尝试获取锁 `synchronized` 没有提供尝试获取锁的功能;一旦开始等待,除非得到锁或者线程被中断(对于支持中断的情况),否则不会返回。然而,`Lock` 接口中的 `tryLock()` 方法可以让线程尝试一次或多次去获取锁,并且可以设置超时时间,这样即使在高并发环境下也能保持较好的性能[^2]。 #### 超时机制 `synchronized` 不同,`Lock` 支持超时机制。这意味着线程可以尝试在给定时间内获取锁,如果超过设定的时间仍未成功,则放弃此次尝试。这对于构建健壮的应用程序非常有用,因为它可以帮助防止无限期地等待锁的情况发生[^4]。 #### 条件变量 每个对象都隐含了一个之关联的监视器,因此使用 `synchronized` 时只能有一个条件队列。但是,`ReentrantLock` 可以创建多个 `Condition` 对象,从而允许多个不同的条件同一个锁相关联。这种方法提高了程序设计的灵活性,因为不同的条件可以独立处理而不互相影响[^4]。 #### 性能 早期版本的 Java (如 JDK 1.5) 中,由于 `synchronized` 是基于操作系统内核态的操作,所以它的效率相对较低。在这种情况下,推荐使用 `Lock` 接口以获得更好的性能表现。不过,在后续的 Java 版本中(比如 JDK 6 及以后),Oracle 对 `synchronized` 进行了大量的优化,包括引入偏向锁、轻量级锁等技术,使得其性能有了显著提升,接近甚至超越了 `Lock` 在某些场景下的表现[^1]。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值