关于synchronized锁和可重入锁

JAVA SDK并发报,最核心的便是对管程的实现。

并发领域的两大问题,互斥和同步:

互斥:同一时刻只允许一个线程访问共享资源,使用Lock解决。

同步:线程之间如何通信,协作?使用Condition解决。

 

这两个关键字与synchronized的区别?

synchronized没办法解决《破坏不可抢占条件》,原因是synchronized申请资源如果申请不到,则线程直接进入阻塞状态了,啥也干不了,对于已经锁定的资源,也不会释放。

而这不是我们希望的,我们希望有这样一把互斥锁:

1、能够响应中断

2、支持超时

3、非阻塞地获取锁

而以上正好对应了Lock接口的三个方法:

1、void lockInterruptibly()

2、boolean tryLock(long time, TimeUnit unit)

3、boolean tryLock();

--------

如何保证可见性?

synchronized关键字是如何保证可见性的呢,实际是通过synchronized的Happen-before规则;

同理,JAVA SDK中的Lock是如何保证可见性的呢?实际也是通过volatile的Happen-before规则,

实际在Lock内部,有一个被声明为volatile的state关键字,在执行加锁和释放锁的同时,会分别进行state的读写,

来保证加锁和解锁,以及下一次加锁代码内,所有变量的值,被刷新到各个工作内存,从而保证类共享成员变量的可见性。

-------

可重入锁

线程可以重复的获得同一把锁

------

使用可重入锁的时候,你可以定义公平锁和非公平锁,灵活配置公平(等待时间长短)策略。

-----

用锁的最佳实践:

1、永远只在更新对象的成员变量时加锁

2、永远只在访问可变的成员变量时加锁

3、永远不要在调用其他对象的方法时加锁

========

Task类的定义

import java.util.LinkedList;
import java.util.List;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

public class Task {

    private final Lock lock = new ReentrantLock();

    private final Condition addCondition = lock.newCondition();

    private final Condition subCondition = lock.newCondition();

    private static int num = 0;

    private volatile List<String> list = new LinkedList<>();


    public void add() {
        lock.lock();

        try {
            while (list.size() == 4) {
                System.out.println("await list size : " + list.size());
                System.out.println("await Current thread : " + Thread.currentThread().getName());
                System.out.println("============");
                this.addCondition.await();
            }

            num++;
            list.add("add banana :" + num);
            System.out.println("list size : " + list.size());
            System.out.println("Current thread : " + Thread.currentThread().getName());
            System.out.println("============");
            this.subCondition.signal();

        } catch (InterruptedException e) {
            System.out.println("=======InterruptedException e=====");
            e.printStackTrace();
        } finally {
            lock.unlock();
        }
    }


    public void sub() {
        lock.lock();

        try {
            while (list.size() == 0) {
                this.subCondition.await();
            }

            num--;
            System.out.println("subtract banana :" + list.get(0));
            list.remove(0);
            System.out.println("list size : " + list.size());
            System.out.println("Current thread : " + Thread.currentThread().getName());
            System.out.println("============");
            this.addCondition.signal();

        } catch (InterruptedException e) {
            System.out.println("=======InterruptedException e=====");
            e.printStackTrace();
        } finally {
            lock.unlock();
        }
    }

}

添加数据和移除数据的线程类:

public class AddThread implements Runnable {
    private Task task;

    public AddThread(Task task) {
        this.task = task;
    }

    @Override
    public void run() {
        this.task.add();
    }
}

public class SubThread implements Runnable {
    private Task task;

    public SubThread(Task task) {
        this.task = task;
    }

    @Override
    public void run() {
        this.task.sub();
    }
}

 测试类:

public class TestReentreLock {
    public static void main(String [] args) {
        Task task = new Task();

        Thread t1 = new Thread(new AddThread(task));
        t1.setName("add Thread 1");
        t1.start();

        Thread t2 = new Thread(new AddThread(task));
        t2.setName("add Thread 2");
        t2.start();

        Thread t3 = new Thread(new AddThread(task));
        t3.setName("add Thread 3");
        t3.start();

        Thread t4 = new Thread(new AddThread(task));
        t4.setName("add Thread 4");
        t4.start();


        Thread t5 = new Thread(new AddThread(task));
        t5.setName("add Thread 5");
        t5.start();


        Thread t6 = new Thread(new AddThread(task));
        t6.setName("add Thread 6");
        t6.start();


        Thread ts1 = new Thread(new SubThread(task));
        ts1.setName("sub Thread 1");
        ts1.start();

        Thread ts2 = new Thread(new SubThread(task));
        ts2.setName("sub Thread 2");
        ts2.start();
    }
}

执行结果:


com.wang.lock.TestReentreLock
list size : 1
Current thread : add Thread 1
============
list size : 2
Current thread : add Thread 3
============
list size : 3
Current thread : add Thread 4
============
list size : 4
Current thread : add Thread 2
============
await list size : 4
await Current thread : add Thread 5
============
await list size : 4
await Current thread : add Thread 6
============
subtract banana :add banana :1
list size : 3
Current thread : sub Thread 1
============
list size : 4
Current thread : add Thread 5
============
subtract banana :add banana :2
list size : 3
Current thread : sub Thread 2
============
list size : 4
Current thread : add Thread 6
============

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值