黑马程序员技术交流社区
标题:
关于lock的小问题
[打印本页]
作者:
ς高眼光の目标
时间:
2014-5-2 05:14
标题:
关于lock的小问题
lock和synchronized有什么区别?
我感觉用起来都一样 lock没什么突出的地方
作者:
张然龙
时间:
2014-5-2 08:29
本帖最后由 张然龙 于 2014-5-2 08:51 编辑
我想说你肯定还没弄清楚 Condition这个类是用来干嘛的。。
Lock这个类与synchronized这个类没有本质上的区别, 但是作为1.5出现的新特性必然有着他的优势,我跟你说一下:
如果出现三个线程或者三个线程以在同一个zynchronized中的情况时,你想用notify方法唤醒的是随机的线程,这个是随机无法控制的。
就像老师生产商品的举例一样,当只有一个出售的线程是运行状态,其他线程挂起,如果notify唤醒的出售线程的话,那么势必就会出现一个商品出售两次的现象!这就导致程序的运行顺序错误!而synchronized也可以解决这个问题:将 if语句修改为while这样只要唤醒的是本方一样会被冻结,这就出现了多次判断!而为了防止所有的线程都进入冻结状态,所以notify方法不能只唤醒单一一个线程,所以应修改为notifyAll方法。
而Lock方法不一样,它内部是可以定义Condition这个类的,他自身定义了一些独有的方法用来操作多线程,Condition的作用你可以参考我以前发的一个帖子。
代码如下↓
/*
下面的代码中有两个对象
Condition con1=lo.newCondition();//con1是指哪些线程? 如何区分?
Condition con2=lo.newCondition();//con2是指哪些线程? 如何区分?
如注释所示, 如何进行区分?con1.await()到底停下的是哪些线程?
con1.signal()到底开启的是哪些线程?
*/
import java.util.concurrent.locks.*;
class Start
{
boolean flag=true;
int x;
Lock lo=new ReentrantLock();
Condition con1=lo.newCondition();//con1是指哪些线程? 如何区分?
Condition con2=lo.newCondition();//con2是指哪些线程? 如何区分?
public void kaishi()
{
while(true)
{
lo.lock();
while(!flag)
{
try {con1.await();} catch (InterruptedException e) {e.printStackTrace();}
}
System.out.println("开始 " +x++);
flag=false;
con2.signal();
lo.unlock();
}
}
public void jieshu()
{
while (true)
{
lo.lock();
while(flag)
{
try {con2.await();} catch (InterruptedException e) {e.printStackTrace();}
}
System.out.println("结束----" +x);
flag=true;
con1.signal();
lo.unlock();
}
}
}
class A implements Runnable
{
Start huan;
A(Start a)
{
this.huan=a;
}
public void run()
{
huan.kaishi();
}
}
class B implements Runnable
{
Start huan;
B(Start a)
{
this.huan=a;
}
public void run()
{
huan.jieshu();
}
}
class Demo2
{
public static void main(String args[])
{
Start s=new Start();
new Thread(new A(s)).start();
new Thread(new A(s)).start();
new Thread(new B(s)).start();
new Thread(new B(s)).start();
}
}
复制代码
因为有四个线程,当第一个线程挂在con1.await();时挂起释放执行权进入冻结状态 ,如果其他线程读到con1.signal();自动将挂在con1.await();的线程唤醒。
如果有多个同时挂起在con1.await();的线程,则随机唤醒一个。同理 con2的对象也是一样。上边的线程生产商品冻结con1,唤醒con2,下边的的线程生产商品冻结con2,唤醒con1,正好实现了互相交替、互不影响的局面!
这就是Lock 与Condition互相搭配的作用
我也是刚才几天学会的多线程,已经把所有的知识点吃透了,所以给你介绍了一遍,有不会的可以加好友探讨下!
作者:
skill20
时间:
2014-5-2 11:35
Lock接口:多线程在JDK1.5版本升级时,推出一个接口Lock接口。
解决线程安全问题使用同步的形式,(同步代码块,要么同步函数)其实最终使用的都是锁机制。
到了后期版本,直接将锁封装成了对象。线程进入同步就是具备了锁,执行完,离开同步,就是释放了锁。
在后期对锁的分析过程中,发现,获取锁,或者释放锁的动作应该是锁这个事物更清楚。所以将这些动作定义在了锁当中,并把锁定义成对象。
所以同步是隐示的锁操作,而Lock对象是显示的锁操作,它的出现就替代了同步。
在之前的版本中使用Object类中wait、notify、notifyAll的方式来完成的。那是因为同步中的锁是任意对象,所以操作锁的等待唤醒的方法都定义在Object类中。
而现在锁是指定对象Lock。所以查找等待唤醒机制方式需要通过Lock接口来完成。而Lock接口中并没有直接操作等待唤醒的方法,而是将这些方式又单独封装到了一个对象中。这个对象就是Condition,将Object中的三个方法进行单独的封装。并提供了功能一致的方法 await()、signal()、signalAll()体现新版本对象的好处。
< java.util.concurrent.locks > Condition接口:await()、signal()、signalAll();
class BoundedBuffer {
final Lock lock = new ReentrantLock();
final Condition notFull = lock.newCondition();
final Condition notEmpty = lock.newCondition();
final Object[] items = new Object[100];
int putptr, takeptr, count;
public void put(Object x) throws InterruptedException {
lock.lock();
try {
while (count == items.length)
notFull.await();
items[putptr] = x;
if (++putptr == items.length) putptr = 0;
++count;
notEmpty.signal();
}
finally {
lock.unlock();
}
}
public Object take() throws InterruptedException {
lock.lock();
try {
while (count == 0)
notEmpty.await();
Object x = items[takeptr];
if (++takeptr == items.length) takeptr = 0;
--count;
notFull.signal();
return x;
}
finally {
lock.unlock();
}
}
}
复制代码
作者:
孙旌棋
时间:
2014-5-3 11:42
以生产者消费者的那个例子解释的话就是, 使用synchronized的话, 你把生产者线程等待后你想要唤醒消费者其他线程, 这时候你只能唤醒其他所有的线程才可以, 万一你唤醒的还是生产者线程呢? 程序就会挂掉的哦
其实吧, Lock替代了synchronized方法和语句, 同时功能更加强大, 不然Lock的出现没有任何意义, Condition替代了Object监视器的方法, 同时功能更加强大, 好处就是释放线程的时候可以选择只释放对方线程, 这样写起来绝对会很爽的哦
为什么呢? 还是生产者消费者的那个例子, 使用 synchronized 的话, 如果想唤醒对方线程, 只有一种方法, 使用notifyAll() 唤醒其他所有线程,否则可能全部等待, 而使用 Lock + Condition的话, 你就可以选择只释放对方线程的
使用 synchronized 的代码
class Goods {
private String name; private int count = 1;
private boolean flag = false;
public synchronized void set(String name) {
while (flag)// 如果用if()循环,操作set的进程就只能有一个
try {
this.wait();// 因为等待在这里的其他操作set的线程不会再判断条件
} catch (InterruptedException e) {}
this.name = name + "--" + count++;
System.out.println("生产者--" + this.name);
flag = true;
this.notifyAll();// notifyAll():唤醒其他所有线程,否则可能全部等待
}
public synchronized void out() {
while (!flag)// 让被唤醒的线程再一次判断标记
try {
this.wait();// wait()冻结当前线程,只能try,不能抛
} catch (InterruptedException e) {}
System.out.println("消费者----"+ this.name);
flag = false;
this.notifyAll();// 因为如果用notify(),可能会只唤醒了本方线程
}
}
class Producer implements Runnable {
private Goods g; Producer(Goods g) {this.g = g;}
public void run() { while (true) { g.set("商品"); }}}
class Consumer implements Runnable {
private Goods g; Consumer(Goods g) {this.g = g;}
public void run() { while (true) { g.out(); }}}
public class SunJingQi {
public static void main(String[] args) { Goods g = new Goods();
new Thread(new Producer(g)).start();
new Thread(new Producer(g)).start();
new Thread(new Consumer(g)).start();
new Thread(new Consumer(g)).start();
}}
复制代码
使用Lock的代码
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
class Goods {
private String name;
private int count = 1;
private boolean flag = false;
// Lock替代了synchronized方法和语句,Condition替代了Object监视器的方法
private Lock lock = new ReentrantLock();
private Condition condition_pro = lock.newCondition();
private Condition condition_con = lock.newCondition();
public void set(String name) throws InterruptedException {
lock.lock();
try {
while (flag)
condition_pro.await();
this.name = name + "--" + count++;
System.out.println("生产者--" + this.name);
flag = true;
condition_con.signal();// 只唤醒对方线程
} finally {
lock.unlock();
}
}
public void out() throws InterruptedException {
lock.lock();
try {
while (!flag)
condition_con.await();
System.out.println("消费者----" + this.name);
flag = false;
condition_pro.signal();// 只唤醒对方线程
} finally {
lock.unlock();
}
}
}
复制代码
欢迎光临 黑马程序员技术交流社区 (http://bbs.itheima.com/)
黑马程序员IT技术论坛 X3.2