Java 锁

一、Java 锁

1.1、公平锁和非公平锁

解释

公平锁解释:多线程情况下,按照申请锁的顺序进行获取锁,先来先得。

非公平锁解释:多线程情况下,获取锁的顺序不是按照申请锁顺序来的。高并发情况下,可能会导致优先级反转或者饥饿现象。

两者区别

公平锁是并发环境下,每个线程获取锁,查看等待队列,如果为空,或线程是等待队列的第一个,则占有锁,否则加入等待队列,按照先进先出规则队列中取到自己。

非公平锁就是上来直接占有锁,尝试失败,在采用公平锁方式。

JAVA 锁

ReentrantLock 属于非公平锁,可以通过构造函数 Booleen值指定,True 公平锁,False 非公平锁。非公平锁优点在于吞吐量比公平锁大
在这里插入图片描述

synchronized 也是非公平锁

1.2、可重入锁(递归锁)原理

可重入锁 最大作用是避免死锁

package com.xin;

import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

/**
 * @author :小心仔
 * @date :Created in 2021/11/4 18:54
 * @description:
 */
public class ReenterLockDemo {

    public static void main(String[] args) {

        Phone phone = new Phone();

        System.out.println("================synchronized================");

        new Thread(() -> {
            phone.sendQQ();
        }, "t1").start();

        new Thread(() -> {
            phone.sendQQ();
        }, "t2").start();

        try { TimeUnit.SECONDS.sleep(1); } catch (InterruptedException e) { e.printStackTrace();}
        System.out.println("================ReentrantLock================");

        Thread t3 = new Thread(phone,"t3");
        Thread t4 = new Thread(phone,"t4");

        t3.start();
        t4.start();

    }

}

class Phone implements Runnable{

    public synchronized void sendQQ() {
        System.out.println(Thread.currentThread().getName() + "\t invoke:sendQQ");
        sendWeChat();
    }

    public synchronized void sendWeChat() {
        System.out.println(Thread.currentThread().getName() + "\t #####invoke:sendWeChat");
    }

    @Override
    public void run() {
        get();
    }

    Lock lock = new ReentrantLock();
    public void get() {
        lock.lock();
        try {
            System.out.println(Thread.currentThread().getName() + "\t invoke:get");
            set();
        } finally {
            lock.unlock();
        }
    }

    public void set() {
        lock.lock();
        try {
            System.out.println(Thread.currentThread().getName() + "\t invoke:set");
        } finally {
            lock.unlock();
        }
    }

}

在这里插入图片描述

1.3、自旋锁(spinlock)

理论

获取线程的锁不会被阻塞,线程会采用循环的方式获取锁,好处减少上下文切换资源浪费,缺点是循环消耗CPU。

代码

package com.xin;

import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicReference;

/**
 * @author :小心仔
 * @date :Created in 2021/11/4 19:32
 * @description:自旋锁Demo
 */
public class SpinlockDemo {


    AtomicReference<Object> atomicReference = new AtomicReference();

    public static void main(String[] args) {
        SpinlockDemo spinlockDemo = new SpinlockDemo();
        new Thread(() -> {
            spinlockDemo.myLock();
            try {
                TimeUnit.SECONDS.sleep(5);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            spinlockDemo.myUnlock();
        }, "AA").start();

        try {
            TimeUnit.SECONDS.sleep(1);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        new Thread(() -> {
            spinlockDemo.myLock();
            spinlockDemo.myUnlock();
        }, "BB").start();
    }

    public void myLock() {
        Thread thread = Thread.currentThread();
        System.out.println(Thread.currentThread().getName() + "come in");

        while (!atomicReference.compareAndSet(null, thread)) {

        }
    }

    public void myUnlock() {
        Thread thread = Thread.currentThread();
        atomicReference.compareAndSet(thread, null);
        System.out.println(Thread.currentThread().getName() + "invoke out");
    }

}

在这里插入图片描述

1.3、读写锁

理论

独占锁(写锁):synchronized、ReentrantLock

共享锁(读锁):

互斥锁:ReadWriteLock

代码

读写锁代码
ReentrantReadWriteLock

package com.xin;

import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.ReentrantReadWriteLock;

/**
 * @author :小心仔
 * @date :Created in 2021/11/4 20:01
 * @description:
 */
public class ReadWriteLockDemo {

    public static void main(String[] args) {

        MyCache myCache = new MyCache();


        for (int i = 1; i <= 5; i++) {
            final int ii = i;
            new Thread(() -> {
                myCache.set(ii + "", ii + "");
                myCache.get(ii + "");
            }, String.valueOf(i)).start();
        }

    }

}

class MyCache {

    private volatile Map<String, Object> map = new HashMap<>();

    ReentrantReadWriteLock reentrantReadWriteLock = new ReentrantReadWriteLock();
    
    public void get(String key) {
        reentrantReadWriteLock.readLock().lock();
        try {
            System.out.println(Thread.currentThread().getName() + "\t 进行读取");
            TimeUnit.MILLISECONDS.sleep(300);
            Object o = map.get(key);
            System.out.println(Thread.currentThread().getName() + "\t 读取值:" + o);
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            reentrantReadWriteLock.readLock().unlock();
        }
    }

    public void set(String key, Object value) {
        reentrantReadWriteLock.writeLock().lock();
        try {
            System.out.println(Thread.currentThread().getName() + "\t 进行写入" + value.toString());
            TimeUnit.MILLISECONDS.sleep(300);
            map.put(key, value);
            System.out.println(Thread.currentThread().getName() + "\t 写入成功");
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            reentrantReadWriteLock.writeLock().unlock();
        }
    }

}

在这里插入图片描述

死锁

产生原因

系统资源不足
资源分配不当

解决办法

jps 命令定位进程号  jps -l
jstack 找到死锁查看 jstack 进程号
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

小心仔

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值