Lock和synchronized的区别
Lock和synchronized的区别
sychronized可重入、不可中断、非公平;Lock可重入、可中断、非公平和公平;
- Lock是一个接口,而synchronized是Java中的关键字,synchronized是内置的语言实现,没有区分读写锁
- synchronized在发生异常时,会自动释放线程占有的锁,因此不会导致死锁现象
发生;而Lock在发生异常时,如果没有主动通过unLock()去释放锁(所以建议使用的
try/finally结构),则很可能造成死锁现象,因此使用Lock时需要在finally块中释放锁
- Lock可以让等待锁的线程响应中断,而synchronized却不行,使用synchronized时,等待的线程会一直等待下去,不能够响应中断
- 通过Lock可以知道有没有成功获取锁,而synchronized却无法办到
Thread类中提供了一个静态方法,可以判断boolean holdsLock(Object obj)
- Lock可以提高多个线程进行读操作的效率。在性能上来说,如果竞争资源不激烈,两者的性能是差不多的,而当竞争资源非常激烈时(即有大量线程同时竞争),此时Lock的性能要远远优于synchronized。所以说,在具体使用时要根据适当情况选择。
条件变量就是表示条件的一种变量。但是必须说明,这里的条件是没有实际含义的,仅仅是个标记而已,并且条件的含义往往通过代码来赋予其含义。条件变量都实现了java.util.concurrent.locks.Condition接口,条件变量的实例化是通过一个Lock对象上调用newCondition()方法来获取的,这样,条件就和一个锁对象绑定起来了。因此,Java中的条件变量只能和锁配合使用,来控制并发程序访问竞争资源的安全。
条件变量Condition接口定义了等待/通知两种类型的方法,在线程调用这些方法时,需要提前获取Condition对象关联的锁(在基于wait/notify方法实现的方案中需要获取的是对象锁)。
Condition对象是需要关联Lock对象的,经调用Lock对象的newCondition()对象创建而来,也就是说Condition的使用是需要依赖Lock对象的。
- await()导致当前线程等待,直到其它线程调用该Condition的signal()方法或者signalAll()方法来唤醒该线程
- signal()唤醒在Lock对象上等待的单个线程。如果所有线程都在该Lock对象上等待,则会选择唤醒其中一个线程。选择是任意的
- signalAll()唤醒在此Lock对象上等待的所有线程。只有当前线程放弃对该Lock对象的锁定后,才可以执行被唤醒的线程
存取款轮流操作,各自5个线程,测试结果是否正确
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
public class Test2 {
public static void main(String[] args) {
Account a=new Account();
for(int i=0;i<5;i++) {
int k=i;
new Thread(()->{
a.cunKuan(k);
}).start();
new Thread(()->{
a.quKuan(k);
}).start();
}
}
}
class Account{
private long id;
private double balance;
private Lock lock=new ReentrantLock();//账户锁
private Condition _save=lock.newCondition();//存款条件,一个锁上可以定义无数个条件变量
private Condition _draw=lock.newCondition();//取款条件
/*
* 存款
* >lock.lock(); 获取锁
* >_save.await(); // 阻塞存款操作, await后就隐示自动释放lock直到被唤醒自动获取
* >_draw.signalAll();// 唤醒所有等待取款线程
* lock.unlock(); // 释放锁
*
* 取款
* > lock.lock(); // 获取锁
* > _draw.await(); // 阻塞取款操作, await后就隐示自动释放lock直到被唤醒自动获取
* > _save.signalAll(); // 唤醒所有存款操作
* > lock.unlock(); // 释放锁
*/
public void cunKuan(double num) {
lock.lock();
try {
System.out.println(Thread.currentThread()+"开始存款");
balance+=num;
System.out.println(Thread.currentThread()+"存款结束");
_save.await();
_draw.signal();
}catch(Exception e) {
e.printStackTrace();
}finally {
lock.unlock();
}
}
public void quKuan(double num) {
lock.lock();
try {
System.out.println(Thread.currentThread()+"开始存款");
balance+=num;
System.out.println(Thread.currentThread()+"存款结束");
_draw.await();
_save.signal();
}catch(Exception e) {
e.printStackTrace();
}finally {
lock.unlock();
}
}
}
生产者消费者
用sychronized和Lock接口分别实现生产者和消费者模式
sychronized
public class Basket {
private volatile Object obj=null;
public synchronized void produce(Object obj) {
while(this.obj!=null) {
try {
this.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
this.obj=obj;
this.notifyAll();
System.out.println("生产了一个对象:"+obj);
}
public synchronized void consume() {
while(this.obj==null) {
try {
this.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println("消费了一个对象:"+obj);
this.obj=null;
this.notifyAll();
}
}
import java.util.Date;
public class Test1 {
public static void main(String[] args) {
Basket basket=new Basket();
Thread t1=new Producer(basket);
Thread t2=new Consumer(basket);
t1.start();
t2.start();
}
}
class Producer extends Thread{
private Basket basket;
public Producer(Basket basket) {
this.basket=basket;
}
@Override
public void run() {
for(int i=0;i<20;i++) {
basket.produce(new Date());
}
}
}
class Consumer extends Thread{
private Basket basket;
public Consumer(Basket basket) {
this.basket=basket;
}
@Override
public void run() {
for(int i=0;i<20;i++) {
basket.consume();
}
}
}
Lock
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
public class Basket2 {
private volatile Object data=null;
private final Lock lock=new ReentrantLock();
private final Condition condition=lock.newCondition();
public void produce(Object data) {
lock.lock();
try {
while(this.data!=null) {
try {
condition.await();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
this.data=data;
condition.signalAll();
System.out.println("生产了一个对象:"+data);
}finally {
lock.unlock();
}
}
public void consume() {
lock.lock();
try {
while(data==null) {
try {
condition.await();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println("消费了一个对象:"+data);
this.data=null;
condition.signalAll();
}finally {
lock.unlock();
}
}
}
import java.util.Date;
public class Test2 {
public static void main(String[] args) {
Basket2 basket=new Basket2();
Thread t1=new Producer2(basket);
Thread t2=new Consumer2(basket);
t1.start();
t2.start();
}
}
class Producer2 extends Thread{
private Basket2 basket;
public Producer2(Basket2 basket) {
this.basket=basket;
}
@Override
public void run() {
for(int i=0;i<20;i++) {
basket.produce(new Date());
}
}
}
class Consumer2 extends Thread{
private Basket2 basket;
public Consumer2(Basket2 basket) {
this.basket=basket;
}
@Override
public void run() {
for(int i=0;i<20;i++) {
basket.consume();
}
}
}
使用生产者消费者模式协调执行顺序
Lock接口
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
public class Operat {
private volatile boolean left=true;
private final Lock lock=new ReentrantLock();
private final Condition ac=lock.newCondition();
private final Condition bc=lock.newCondition();
public void printA() {
lock.lock();
try {
while(!left)
try {
ac.await();
} catch (InterruptedException e) {
e.printStackTrace();
}
left=false;
System.out.println("A::"+Thread.currentThread());
bc.signal();
}finally {
lock.unlock();
}
}
public void printB() {
lock.lock();
try {
while(left) {
try {
bc.await();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
left=true;
System.out.println("B::"+Thread.currentThread());
ac.signal();
}finally {
lock.unlock();
}
}
}
public class Test2 {
public static void main(String[] args) {
Operat op = new Operat();
for (int k = 0; k < 5; k++) {
Thread leftHandle = new Thread(() -> {
for (int i = 0; i < 10; i++) {
op.printA();
}
});
Thread rightHandle = new Thread(() -> {
for (int i = 0; i < 10; i++) {
op.printB();
}
});
leftHandle.start();
rightHandle.start();
}
}
}
Synchronized
public class Operation {
private volatile boolean left=true;
public synchronized void printA() {
while(!left) {
// System.out.println("A:"+Thread.currentThread()+"begin...");
try {
this.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
left=false;
System.out.println("A::"+Thread.currentThread());
this.notifyAll();
}
public synchronized void printB() {
while(left) {
// System.out.println("B:"+Thread.currentThread()+"begin...");
try {
this.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
left=true;
System.out.println("B::"+Thread.currentThread());
this.notifyAll();
}
}
public class Test1 {
public static void main(String[] args) {
Operation op = new Operation();
for (int k = 0; k < 5; k++) {
Thread leftHandle = new Thread(() -> {
for (int i = 0; i < 10; i++) {
op.printA();
}
});
Thread rightHandle = new Thread(() -> {
for (int i = 0; i < 10; i++) {
op.printB();
}
});
leftHandle.start();
rightHandle.start();
}
}
}