个人博客
专注IT梦想的地方

java线程中synchronized锁和升级替换锁

在之前的文章《java中关于线程安全问题的详细说明》中其实有讲到关于线程的安全问题,那么就引入了一个关于安全锁synchronized的两种用法,那么其实在synchronized的两种用法中还是会存在一定的问题。

举一个例子:

我们假定一个生产者,一个消费者,在对烤鸭这个资源进行生产和消费,那么这个时候可以正常的使用到synchronized的两种用法,但是如果当多个生产者和多个消费者来进行轮流替换时,也就是生产者生产了一只烤鸭的情况下消费者才能消费一只烤鸭,然后再允许生产者生产第二只烤鸭,消费者再消费第二只烤鸭,以此类推,这个时候就会导致程序出现死锁的情况。

这时我们就需要引入两个方法notify和notifyAll

notify:只能唤醒一个线程,如果本方唤醒了本方,没有意义,而且while判断标记+notify会导致死锁。

notifyAll:解决了本方线程一定会唤醒对方线程的问题。

所以这个时候我们就能很好的解决了关于多生产者和多消费者之间的安全存在问题。

if判断标记,只有一次,会导致不该运行的线程运行了,出现了数据错误的情况。
while判断标记,解决了线程获取执行权后,是否要运行!

例如:

class ky{
private String name;
private int sl=1;
private boolean flag=false;
public synchronized void set(String name){
while(flag)
try {
this.wait();
} catch (InterruptedException e) {
}
this.name=name+sl;
sl++;
System.out.println(Thread.currentThread().getName()+”…生产者…”+this.name);
flag=true;
notifyAll();
}

public synchronized void out(){
while(!flag)
try {
this.wait();
} catch (InterruptedException e) {
}
System.out.println(Thread.currentThread().getName()+”…消费者…”+this.name);
flag=false;
notifyAll();
}
}

class scz implements Runnable{
private ky r;
scz(ky r){
this.r=r;
}
public void run(){
while(true){
r.set(“烤鸭”);
}
}
}
class xfz implements Runnable{
private ky r;
xfz( ky r){
this.r=r;
}
public void run(){
while(true){
r.out();
}
}
}
public class ProducerConsumerDemo {
public static void main(String[] args){
ky k=new ky();
scz s=new scz(k);
xfz x=new xfz(k);

Thread t0=new Thread(s);
Thread t1=new Thread(s);
Thread t2=new Thread(x);
Thread t3=new Thread(x);
t0.start();
t1.start();
t2.start();
t3.start();
}
}

 

那么这样就解决了死锁的问题,可是这样的思想在java中是比较落后的,因为在java1.5即java5.0之后运用java的面向对象的思想,重新对安全锁这个概念进行了升级优化。

如下:

import java.util.concurrent.locks.*;
class ky{
private String name;
private int sl=1;
private boolean flag=false;
//创建锁对象
Lock lock=new ReentrantLock();
//通过已有的锁获取该锁上的监视器对象。
Condition l1 = lock.newCondition();
Condition l2 = lock.newCondition();
public void set(String name){
lock.lock();
try {
while(flag)
try {
l1.await();
} catch (InterruptedException e) {
}
this.name=name+sl;
sl++;
System.out.println(Thread.currentThread().getName()+”…生产者5.0…”+this.name);
flag=true;
l2.signal();
}
finally{
lock.unlock();
}

}

public void out(){
lock.lock();
try {
while(!flag)
try {
l2.await();
} catch (InterruptedException e) {
}
System.out.println(Thread.currentThread().getName()+”…消费者5.0…”+this.name);
flag=false;
l1.signal();
}
finally{
lock.unlock();
}

}
}

class scz implements Runnable{
private ky r;
scz(ky r){
this.r=r;
}
public void run(){
while(true){
r.set(“烤鸭”);
}
}
}
class xfz implements Runnable{
private ky r;
xfz( ky r){
this.r=r;
}
public void run(){
while(true){
r.out();
}
}
}
public class ProducerConsumerDemo {
public static void main(String[] args){
ky k=new ky();
scz s=new scz(k);
xfz x=new xfz(k);

Thread t0=new Thread(s);
Thread t1=new Thread(s);
Thread t2=new Thread(x);
Thread t3=new Thread(x);
t0.start();
t1.start();
t2.start();
t3.start();
}
}

那么jdk1.5以后将同步和锁封装成了对象,并将操作锁的隐式方式定义到了该对象中,将隐式动作编程了显示动作,既使用Lock和Condition接口来进行优化。

 

Lock接口:它的出现替代了同步代码块或者同步函数,将同步的隐式锁操作变成显示锁操作,同时更为灵活,可以一个锁上加上多组监视器。

lock():获取锁。

unlock():释放锁,通常需要定义finally代码块中。

 

Condition接口:它的出现替代了Object中的wait、notify和notifyAll方法。将这些监视器方法单独进行了封装,变成Condition监视器对象,可以任意锁进行组合。

await()相当于wait()

signal()相当于notify()

signalAll()相当于notifyAll()

赞(0) 打赏
未经允许,不得转载本站任何文章:智言个人博客 » java线程中synchronized锁和升级替换锁

评论 抢沙发

评论前必须登录!

 

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

微信扫一扫打赏