简单说说重入锁与读写锁

先说说重入锁,既然说到了重入锁,那么也顺带提一下不可重入锁(自旋锁)吧。

这两个概念实际上很好区分,

重入锁:

就如同在饭堂打饭,你在窗口排着队。排到你的时候,突然路人A让你顺带着打个饭吧,然后你就打了两份饭,这时候你还没离开窗口,又有路人B让你打一份汤,于是你又额外打了一份汤。

即:可重入锁,也叫做递归锁,指的是同一线程 外层函数获得锁之后 ,内层递归函数仍然有获取该锁的代码,但不受影响。(本来想自己总结一下,发现不靠谱)

在Java中,ReentrantLock和Synchronized都是可重入锁。

/**
 * Created by Anur IjuoKaruKas on 2017/11/14.
 * Description :
 */
public class Restaurant {
    private Lock windows = new ReentrantLock();

    public void getMeals() throws Exception {
        try {
            windows.lock();
            Thread.sleep(1000);
            System.out.println(Thread.currentThread().getName() + "打饭");
        } finally {
            windows.unlock();
        }
    }

    public void getSoup() throws Exception {
        try {
            windows.lock();
            Thread.sleep(1000);
            System.out.println(Thread.currentThread().getName() + "打汤");
        } finally {
            windows.unlock();
        }
    }

    public void today() throws Exception {
        try {
            windows.lock();
            Thread.sleep(1000);
            System.out.println(Thread.currentThread().getName() + "打饭");
            getMeals();
            getSoup();
        } finally {
            windows.unlock();
        }
    }

    public static void main(String[] args) {
        Restaurant test = new Restaurant();
        new Thread(() -> {
            try {
                test.today();
            } catch (Exception e) {
                e.printStackTrace();
            }
        }, "我").start();

        new Thread(() -> {
            try {
                test.getSoup();
            } catch (Exception e) {
                e.printStackTrace();
            }
        }, "某人").start();

        new Thread(() -> {
            try {
                test.getMeals();
            } catch (Exception e) {
                e.printStackTrace();
            }
        }, "另一个人").start();
    }
}

输出:
我打饭
我打饭
我打汤
某人打汤
另一个人打饭

不可重入锁(自旋锁):

在另一个菜式比较好吃且热门的窗口,可不是这样的,在这里你在窗口,只能点一个菜(进入一次临界区),点完后,你想要再点别的菜,只能重新排一次队(虽然可以插队,当然我们可以引入服务员队伍管理机制:private Lock windows = new ReentrantLock(true);,指定该锁是公平的。)

即:自旋锁是专为防止多处理器并发而引入的一种锁,它在内核中大量应用于中断处理等部分。

public class Restaurant {
    boolean isLock = false;

    public synchronized void getMeals() throws Exception {
        while (isLock) {
            wait();
        }
        isLock = true;
        try {
            Thread.sleep(1000);
            System.out.println(Thread.currentThread().getName() + "打饭");
        } finally {
            isLock = false;
        }
    }

    public synchronized void getSoup() throws Exception {
        while (isLock) {
            wait();
        }
        isLock = true;
        try {
            Thread.sleep(1000);
            System.out.println(Thread.currentThread().getName() + "打汤");
        } finally {
            isLock = false;
        }
    }

    public void today() throws Exception {
        while (isLock) {
            wait();
        }
        isLock = true;
        try {
            Thread.sleep(1000);
            System.out.println(Thread.currentThread().getName() + "打饭");
            getSoup();
        } finally {
            isLock = false;
        }
    }

    public static void main(String[] args) {
        Restaurant test = new Restaurant();
        new Thread(() -> {
            try {
                test.today();
            } catch (Exception e) {
                e.printStackTrace();
            }
        }, "我").start();

        new Thread(() -> {
            try {
                test.getSoup();
            } catch (Exception e) {
                e.printStackTrace();
            }
        }, "某人").start();

        new Thread(() -> {
            try {
                test.getMeals();
            } catch (Exception e) {
                e.printStackTrace();
            }
        }, "另一个人").start();
    }
}

输出:
我打饭

然后死锁了……

读写锁:

然而餐次的人流量一大,老板发现经常排起很长的队伍,厨师却都闲着没事干。老板拍脑子一想,这样不行啊,所以稍微改进了一下点餐方式。所有人都可以扫二维码用H页进行点餐,只要这个菜不是正在做(写锁),那么就可以随便点。

即:假设你的程序中涉及到对一些共享资源的读和写操作,且写操作没有读操作那么频繁。在没有写操作的时候,两个线程同时读一个资源没有任何问题,所以应该允许多个线程能在同时读取共享资源。但是如果有一个线程想去写这些共享资源,就不应该再有其它线程对该资源进行读或写。

/**
 * Created by Anur IjuoKaruKas on 2017/11/14.
 * Description :
 */
public class Restaurant {
    private ReentrantReadWriteLock food = new ReentrantReadWriteLock();
    private ReentrantReadWriteLock.ReadLock getFoodLock = food.readLock();
    private ReentrantReadWriteLock.WriteLock cookingLock = food.writeLock();

    public void getFood() throws Exception {
        try {
            getFoodLock.lock();
            System.out.println(Thread.currentThread().getName() + "点饭");
        } finally {
            getFoodLock.unlock();
        }
    }

    public void cooking() throws Exception {
        try {
            cookingLock.lock();
            Thread.sleep(1000);
            System.out.println(Thread.currentThread().getName() + "做菜");
        } finally {
            cookingLock.unlock();
        }
    }

    public static void main(String[] args) {
        Restaurant test = new Restaurant();
        for (int i = 0; i < 10; i++) {
            new Thread(() -> {
                try {
                    test.getFood();
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }, "某人").start();
            if (i == 2) {
                new Thread(() -> {
                    try {
                        test.cooking();
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                }, "厨师").start();
            }
        }
    }
}

输出:
某人点饭
某人点饭
某人点饭
厨师做菜
==等待1秒==
某人点饭
某人点饭
某人点饭
某人点饭
某人点饭
某人点饭
某人点饭

转载于:https://my.oschina.net/anur/blog/1573625

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值