黑马程序员技术交流社区
标题:
多线程 synchronized 与 lock
[打印本页]
作者:
于海龙
时间:
2013-5-2 09:50
标题:
多线程 synchronized 与 lock
本帖最后由 于海龙 于 2013-5-3 09:29 编辑
两者有什么区别, 如何选择使用。
作者:
harborbest
时间:
2013-5-2 10:01
synchronized有两种用法,一种是在方法定义时使用,多线程状态下,这个方法只能同时被同一个线程执行;另一种用于锁定代码段,也就是说,{ }括号中的代码是不会同时被多个线程执行,而是排队执行。
线程A和B都要获取对象O的锁定,假设A获取了对象O锁,B将等待A释放对O的锁定,
如果使用 synchronized ,如果A不释放,B将一直等下去,不能被中断
如果 使用Lock,如果A不释放,可以使B在等待了足够长的时间以后,中断等待,而干别的事情
synchronized是在JVM层面上实现的,不但可以通过一些监控工具监控synchronized的锁定,而且在代码执行时出现异常,JVM会自动释放锁定,但是使用Lock则不行,lock是通过代码实现的,要保证锁定一定会被释放,就必须将unLock()放到finally{}中
作者:
刘学明
时间:
2013-5-2 10:23
本帖最后由 刘学明 于 2013-5-2 10:25 编辑
首先 Lock是 JDK1.5版本后的新特性
Lock替代了synchronized
Condition对象替代了锁对象
一:代码层的区别:
public void method(){
synchronized(this){ //旧锁 ,无需人工释放
try(this.wait()}catch(Exception e){}
System.out.println();
this.notifyAll();
}
}
public void method2(){
Lock lock = new ReentrantLock();
Condition condition = lock.newCondition();
lock.lock();//上锁
try{
try{condition.await();}catch(Exception e){}
System.out.println("..");
condition.signalAll();
}finally{
lock.unlock();
}
}
复制代码
在高并发时,Lock性能 优势很明显 ,在低并发时,synchronized也能取得优势 。
代码示例:
lass Resource
{
private String name;
private int count = 1;
private boolean flag = false;
// t1 t2
private Lock lock = new ReentrantLock();
private Condition condition_pro = lock.newCondition(); //当多线程并发时 使用Lock机制可以创建两个Condition对象
private Condition condition_con = lock.newCondition();
public void set(String name)throws InterruptedException
{
lock.lock();
try
{
while(flag)
condition_pro.await();//t1,t2 //冻结生产方
this.name = name+"--"+count++;
System.out.println(Thread.currentThread().getName()+"...生产者.."+this.name);
flag = true;
condition_con.signal();// 可以只唤醒消费方,而没有唤醒生产方
}
finally
{
lock.unlock();//释放锁的动作一定要执行。
}
}
// t3 t4
public void out()throws InterruptedException
{
lock.lock();
try
{
while(!flag)
condition_con.await();//冻结消费方
System.out.println(Thread.currentThread().getName()+"...消费者........."+this.name);
flag = false;
condition_pro.signal(); //只唤醒生产方 没唤醒消费方
}
finally
{
lock.unlock();
}
}
}
class Producer implements Runnable
{
private Resource res;
Producer(Resource res)
{
this.res = res;
}
public void run()
{
while(true)
{
try
{
res.set("+商品+");
}
catch (InterruptedException e)
{
}
}
}
}
class Consumer implements Runnable
{
private Resource res;
Consumer(Resource res)
{
this.res = res;
}
public void run()
{
while(true)
{
try
{
res.out();
}
catch (InterruptedException e)
{
}
}
}
}
复制代码
综合来看,对于所有的高并发情况,采用Lock加锁是最优选择, 但是由于历史遗留等问题 synchronized也还是不能完全淘汰 同时 在低并发的情况下,synchronized的性能还是比Lock要好的
作者:
刘胜寒
时间:
2013-5-2 10:42
受教了...
作者:
余雷
时间:
2013-5-2 11:30
主要相同点:Lock能完成Synchronized所实现的所有功能。
主要不同点:Lock有比Synchronized更精确的县城予以和更好的性能。Synchronized会自动释放锁,但是Lock一定要求程序员手工释放,并且必须在finally从句中释放。
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需要手动关闭
欢迎光临 黑马程序员技术交流社区 (http://bbs.itheima.com/)
黑马程序员IT技术论坛 X3.2