Java 并发时的 "互斥锁"机制

一、两种互斥机制

Java 提供了两种互斥锁用来解决在共享资源时存在的并发问题。

一种方式是提供synchronized 关键字,当任务要执行被synchronized 关键字保护的代码片段的时候,它会检查所可用,然后获取锁,执行代码,释放锁。

另一种方式是显式的使用Lock 对象,在Java SE5 中的java.util.concurrent.locks 类库中定义了这个对象,Lock 对象必须被显式的创建,锁定和释放。下面通过一个例子来体验一下两种锁机制有什么不同:创建三个线程并发访问任务,在任务中输出99-1的数字,为了达到效果在输出之前让线程睡了100ms。

synchronized 同步代码方式:

public class SynchronizedTest {
    public static void main(String[] args) {
        LockDemo2 demo2 = new LockDemo2();
        new Thread(demo2,"一号线程").start();
        new Thread(demo2,"二号线程").start();
        new Thread(demo2,"三号线程").start();
    }
}
class LockDemo2 implements Runnable{
    private int num = 100;

    @Override
    public void run() {
        while(true){
            synchronized(this){
                if(num > 1){
                    try {
                        Thread.sleep(100);
                        System.out.println(Thread.currentThread().getName()+"剩余数量为:" + --num);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                } else {
                    break;
                }
            }
        }
    }
}

显式Lock 锁方式:

public class LockTest {
    public static void main(String[] args) {

        LockDemo demo = new LockDemo();
        new Thread(demo,"一号线程").start();
        new Thread(demo,"二号线程").start();
        new Thread(demo,"三号线程").start();
    }
}

class LockDemo implements Runnable{
    private int num = 100;
    private Lock lock = new ReentrantLock();

    @Override
    public void run() {
        while(true){
            lock.lock();
            try {
                if(num > 1){
                    Thread.sleep(100);
                    System.out.println(Thread.currentThread().getName()+"剩余数量为:" + --num);
                }else{
                    break;
                }
            } catch (InterruptedException e) {
                e.printStackTrace();
            }finally {
                lock.unlock();
            }
        }
    }
}

二、对比

上面两种方式都能解决在并发执行时解决共享资源的问题,那么这两种方式有什么不同呢?

synchronized 方法或语句的使用提供了对与每个对象相关的隐式监视器锁的访问,但却强制所有锁获取和释放均要出现在一个块结构中:当获取了多个锁时,它们必须以相反的顺序释放,且必须在与所有锁被获取时相同的词法范围内释放所有锁。 而且它比Lock 显式锁方式写出来的代码要更优雅,但是在解决某些问题时它却不如Lock 灵活,比如:某些遍历并发访问的数据结果的算法要求使用 “hand-over-hand” 或 “chain locking”:获取节点 A 的锁,然后再获取节点 B 的锁,然后释放 A 并获取 C,然后释放 B 并获取 D,依此类推。

Lock 显式锁正如上面所说的,它比synchronized 更加灵活,而且有的时候解决一些特殊的问题。在使用Lock 时要注意在加锁后一定要释放锁,为了使锁能够得到释放,你必须将unlock() 方法定义在finally 语句块中,这样做也有一个优点就是如果在代码同步的时候出现了错误,你可以在finally 子句对出现的错误进行维护。Lock 的实现类中还提供了很多强大的功能,就留在以后再写吧。

    原文作者:java锁
    原文地址: https://blog.csdn.net/codejas/article/details/78774241
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞