synchronized同步的弊端以及Lock针对的解决方案

线程安全

如果当我们启动了两个线程,一个修改一个对象的数据 ,一个输出同一个对象的数据。
这个时候如果我们不做出同步的时候,是会引发线程安全的问题。

synchronized代码块

class Demo implements Runable{
private Object obj = new Object();

public void run(){
    while(true){
        synchronized(obj){code...}
        }
    }

}

这里是什么意思呢?

synchronized(obj)

当运行到这步的时候,判断obj是否被其他的线程拿到,
如果是将不能运行代码里面的东西。如果没有被其他线程拿到 ,那将可以运行代码块里的东西。
那obj在synchronized的参数里算是什么呢?
我们称之为锁。
在这里BZ的理解觉得有点像if语句
if(obj是否被别的线程拿了,如果拿了就进不能进去){}
其实synchronized并不是在一开始才判断 ,后面会解说。

synchronized方法

并不是只有代码块,还可以做函数,
代码体现:

public synchronized void method(){}

其实含义也和代码块也差不多,看看锁是否被拿 拿了 将无法进行执行。
如果不知道的肯定会很疑惑,那么synchronized方法锁是谁,其实是this.
这也是synchronized代码 块和synchronized方法的区别,代码块是可以自己想是谁就谁。

延伸, static 的synchronized 方法。

如果是static 的时候,大家肯定都知道 (如果看过我前面文章的话),static方法是在创建类之前就有的 ,如果在加载static 方法到内存的时候,没有这个类 ,将会报错。所以这里锁肯定不会是this,那么除了this 还有谁呢? 大家都知道静态是在类里的唯一对象。那个描述的文件,类.class(bz也不知道怎么解释哈哈),所以它的锁就是当前对象的类文件。

synchronized弊端

一.死锁

有两种情况下会导致死锁的发生
1..当线程任务中出现了多个同步(多个锁)时,如果同步中嵌套了
其他的同步。这时容易引发一种现象,死锁。
代码体现:

boolean trueorfalse = true;
Object obj1 = new Object();
Object obj2 = new Object();
if(trueorfalse){

while(true){
    synchronized(obj1){synchronized(obj2){code..}}
}

else{

while(true){
    synchronized(obj2){synchronized(obj1){code..}}
}

}

如果这样会进行死锁

2..另外一种死锁 就是 所有线程都被wait 没有另一个线程唤醒这些线程

二.不能控制notify对指定线程的唤醒

锁与监视器

当我们在synchronized 里面 调用 wait 方法时 , 该线程就会等待下来,那么当我们要唤醒他的时候,那我们该如何找到被等待下来的线程?
其实这个线程就在该锁的线程池上,那又谁来操作这一系列的动作呢 ,
就是监视器。那么监视器和锁是几对几的呢?这是我们值得思考的问题。
接下来我们来看一下的代码:

class UtilDemo{
boolean flag = false;

public synchronized void run1(){
    if(flag)
        try{this.wait();}catch(InterruptException e ){}
    flag=true;
    this.notify();
}
public synchronized void run2(){
    if(!flag)
        try{this.wait();}catch(InterruptException e ){}
    flag=false;
    this.notify();
}

}
class runable1 implements Runable{

private UtilDemo u ;
public runable1(UtilDemo u){
    this.u = u;
}
public void run(){
    while(true){
        u.run1();
    }
}

}
class runable2 implements Runable{

private UtilDemo u ;
public runable2(UtilDemo u){
    this.u = u;
}
public void run(){
    u.run2();
}

}
public class MainDemo{

public static void main(String[] args){
    UtilDemo u = new UtilDemo();
    Runable run1 = new Runable1(u);
    Runable run2 = new Runable2(u);
    Thread t1 = new Thread(run1);
    Thread t2 = new Thread(run1);
    Thread t3 = new Thread(run2);
    Thread t4 = new Thread(run2);
    t1.start();
    t2.start();
    t3.start();
    t4.start();
}

}

当我们启动多个线程的时候后,会出现多个线程等待的情况下,只有一个线程没被等待,当我们这时候调用notify() ,这时候就纠结了到底是唤醒哪一个呢?监视器还提供了一个方法 notifyAll(),但是这是不利于我们的程序的。

Locks

在java .util .concurrent.locks 中有针对的解决方案。
Lock接口,比同步更厉害,有更多的操作。

在JDK1.5中 ,同步改成了Lock
那么原来的锁上的监视器方法(wait,notify,notifyAll)
也应该替换成新锁的监视器方法。
jdk1.5 中将这些原有的监视器方法封装到一个Condition对象中,想要获得监视器方法,需要先获取Condition对象。
Condition 对象的出现其实就是替代了Object中的监视器方法。
所以我们可以对以上代码进行改编:

class UtilDemo{
boolean flag = false;
Lock lock = new Lock();
Condition con1 = lock.newCondition();
Condition con2 = lcok.newCondition();

public void run1(){
    try{
        lock.lock();
        if(flag)
            try{con1.wait();}catch(InterruptException e ){}
        flag=true;
        con2.notify();
    }finally{
        lock.unlock();
    }
}
public void run2(){
    try{
        lock.lock();
        if(!flag)
            try{con2.wait();}catch(InterruptException e ){}
        flag=false;
        con1.notify();
    }finally{
        lock.unlock();
    }
}

}
class runable1 implements Runable{

private UtilDemo u ;
public runable1(UtilDemo u){
    this.u = u;
}
public void run(){
    while(true){
        u.run1();
    }
}

}
class runable2 implements Runable{

private UtilDemo u ;
public runable2(UtilDemo u){
    this.u = u;
}
public void run(){
    u.run2();
}

}
public class MainDemo{

public static void main(String[] args){
    UtilDemo u = new UtilDemo();
    Runable run1 = new Runable1(u);
    Runable run2 = new Runable2(u);
    Thread t1 = new Thread(run1);
    Thread t2 = new Thread(run1);
    Thread t3 = new Thread(run2);
    Thread t4 = new Thread(run2);
    t1.start();
    t2.start();
    t3.start();
    t4.start();
}

}
这样我们将就可以对指定的线程唤醒了。

synchronized和Locks区别在哪?

左边为synchronized,右边为Locks
Condition对象里面封装了Object 中监视器的方法。
await():会让线程处于等待状态,其实就是将线程临时存储到线程池中。
signal():会唤醒线程池中任意一个等待的线程。
signalAll():会唤醒线程池中所有的等待线程。
那么这样两种方式没什么区别 不过就是重新封装了一次
区别在于
第一种方法锁是和监视器绑在一起 一个锁只能有一个监视器
第二种方法锁是和监视器分开 Lock 、Condition 一个锁能同时有两个监视器

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值