java中的锁

公平锁/非公平锁

 

 

 

可重入锁

指的是以线程为单位,当一个线程获取对象锁之后,这个线程可以再次获取本对象上的锁,而其他的线程是不可以的。

public class ReenterLockTest {
    public static void main(String[] args) {
        new Thread(()->{
            reenterLock_DaMen();
        }).start();
        new Thread(()->{
            reenterLock_DaMen();
        }).start();
    }
    private static void reenterLock_DaMen() {
        synchronized (ReenterLockTest_Phone.class){
            System.out.println(Thread.currentThread().getName()+"打开大门");
            try {
                TimeUnit.SECONDS.sleep(3);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            reenterLock_room();
        }
    }

    private static void reenterLock_room() {
        synchronized (ReenterLockTest_Phone.class){
            System.out.println(Thread.currentThread().getName()+"打开房间门");
        }
    }
}

 

自旋锁

底层原理

缺点

循环会耗时

只能一个自变量的原子性

ABA

import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicStampedReference;

public class ABATest {
    public static void main(String[] args) {
        //ABA();
        resolveABA();
    }

    /**
     * "D:\Program Files\Java\jdk1.8.0_131\bin\java.exe" "-javaagent:D:\Program Files\IntelliJ IDEA 2019.3.4\lib\idea_rt.jar=51279:D:\Program Files\IntelliJ IDEA 2019.3.4\bin" -Dfile.encoding=UTF-8 -classpath "D:\Program Files\Java\jdk1.8.0_131\jre\lib\charsets.jar;D:\Program Files\Java\jdk1.8.0_131\jre\lib\deploy.jar;D:\Program Files\Java\jdk1.8.0_131\jre\lib\ext\access-bridge-64.jar;D:\Program Files\Java\jdk1.8.0_131\jre\lib\ext\cldrdata.jar;D:\Program Files\Java\jdk1.8.0_131\jre\lib\ext\dnsns.jar;D:\Program Files\Java\jdk1.8.0_131\jre\lib\ext\jaccess.jar;D:\Program Files\Java\jdk1.8.0_131\jre\lib\ext\jfxrt.jar;D:\Program Files\Java\jdk1.8.0_131\jre\lib\ext\localedata.jar;D:\Program Files\Java\jdk1.8.0_131\jre\lib\ext\nashorn.jar;D:\Program Files\Java\jdk1.8.0_131\jre\lib\ext\sunec.jar;D:\Program Files\Java\jdk1.8.0_131\jre\lib\ext\sunjce_provider.jar;D:\Program Files\Java\jdk1.8.0_131\jre\lib\ext\sunmscapi.jar;D:\Program Files\Java\jdk1.8.0_131\jre\lib\ext\sunpkcs11.jar;D:\Program Files\Java\jdk1.8.0_131\jre\lib\ext\zipfs.jar;D:\Program Files\Java\jdk1.8.0_131\jre\lib\javaws.jar;D:\Program Files\Java\jdk1.8.0_131\jre\lib\jce.jar;D:\Program Files\Java\jdk1.8.0_131\jre\lib\jfr.jar;D:\Program Files\Java\jdk1.8.0_131\jre\lib\jfxswt.jar;D:\Program Files\Java\jdk1.8.0_131\jre\lib\jsse.jar;D:\Program Files\Java\jdk1.8.0_131\jre\lib\management-agent.jar;D:\Program Files\Java\jdk1.8.0_131\jre\lib\plugin.jar;D:\Program Files\Java\jdk1.8.0_131\jre\lib\resources.jar;D:\Program Files\Java\jdk1.8.0_131\jre\lib\rt.jar;E:\coding\java1.0\target\classes;E:\coding\java1.0\src\main\java\lib\commons-io-2.6.jar;C:\Users\86157\.m2\repository\org\projectlombok\lombok\1.18.24\lombok-1.18.24.jar;C:\Users\86157\.m2\repository\junit\junit\4.12\junit-4.12.jar;C:\Users\86157\.m2\repository\org\hamcrest\hamcrest-core\1.3\hamcrest-core-1.3.jar" com.fh.thread.locks.spinlock.ABATest
     * A1 = >1
     * B1 = >1
     * b2 = >true
     * A2 = >false
     * b2 = >值:6;版本号:2
     * A2 = >值:6;版本号:2
     * A3 = >false
     * A3 = >值:6;版本号:2
     */
    private static void resolveABA() {
        AtomicStampedReference<Integer> atomicInteger = new AtomicStampedReference<>(1, 1);//初始值,版本号时间戳

        new Thread(() -> {
            int stamp = atomicInteger.getStamp();//获得版本号
            System.out.println("A1 = >" + stamp);
            try {
                TimeUnit.SECONDS.sleep(2);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            //最后两个参数,拿到最新的版本号,把版本号+1
            System.out.println("A2 = >" + atomicInteger.compareAndSet(1, 2, atomicInteger.getStamp(), atomicInteger.getStamp() + 1));
            System.out.println("A2 = >值:" + atomicInteger.getReference() + ";版本号:" + atomicInteger.getStamp());
            //把这个值该回去
            System.out.println("A3 = >" + atomicInteger.compareAndSet(2, 1, atomicInteger.getStamp(), atomicInteger.getStamp() + 1));
            System.out.println("A3 = >值:" + atomicInteger.getReference() + ";版本号:" + atomicInteger.getStamp());

        }, "a").start();


        new Thread(() -> {
            int stamp = atomicInteger.getStamp();//获得版本号
            System.out.println("B1 = >" + stamp);

            try {
                TimeUnit.SECONDS.sleep(2);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("b2 = >" + atomicInteger.compareAndSet(1, 6, stamp, stamp + 1));
            System.out.println("b2 = >值:" + atomicInteger.getReference() + ";版本号:" + atomicInteger.getStamp());
        }, "b").start();
    }

    /**
     * 【1、原来的值1,更新为2】
     * true
     * 2
     * 【2、中间偷偷把2更新为原来的值1】
     * true
     * 1
     * 【3、因为第二步,把新值又更新为原来的值,所以此次以为原来的值没有更改过】
     * true
     * 11
     */
    private static void ABA() {
        AtomicInteger atomicInteger = new AtomicInteger(1);
        System.out.println("【1、原来的值1,更新\"D:\\Program Files\\Java\\jdk1.8.0_131\\bin\\java.exe\" \"-javaagent:D:\\Program Files\\IntelliJ IDEA 2019.3.4\\lib\\idea_rt.jar=51279:D:\\Program Files\\IntelliJ IDEA 2019.3.4\\bin\" -Dfile.encoding=UTF-8 -classpath \"D:\\Program Files\\Java\\jdk1.8.0_131\\jre\\lib\\charsets.jar;D:\\Program Files\\Java\\jdk1.8.0_131\\jre\\lib\\deploy.jar;D:\\Program Files\\Java\\jdk1.8.0_131\\jre\\lib\\ext\\access-bridge-64.jar;D:\\Program Files\\Java\\jdk1.8.0_131\\jre\\lib\\ext\\cldrdata.jar;D:\\Program Files\\Java\\jdk1.8.0_131\\jre\\lib\\ext\\dnsns.jar;D:\\Program Files\\Java\\jdk1.8.0_131\\jre\\lib\\ext\\jaccess.jar;D:\\Program Files\\Java\\jdk1.8.0_131\\jre\\lib\\ext\\jfxrt.jar;D:\\Program Files\\Java\\jdk1.8.0_131\\jre\\lib\\ext\\localedata.jar;D:\\Program Files\\Java\\jdk1.8.0_131\\jre\\lib\\ext\\nashorn.jar;D:\\Program Files\\Java\\jdk1.8.0_131\\jre\\lib\\ext\\sunec.jar;D:\\Program Files\\Java\\jdk1.8.0_131\\jre\\lib\\ext\\sunjce_provider.jar;D:\\Program Files\\Java\\jdk1.8.0_131\\jre\\lib\\ext\\sunmscapi.jar;D:\\Program Files\\Java\\jdk1.8.0_131\\jre\\lib\\ext\\sunpkcs11.jar;D:\\Program Files\\Java\\jdk1.8.0_131\\jre\\lib\\ext\\zipfs.jar;D:\\Program Files\\Java\\jdk1.8.0_131\\jre\\lib\\javaws.jar;D:\\Program Files\\Java\\jdk1.8.0_131\\jre\\lib\\jce.jar;D:\\Program Files\\Java\\jdk1.8.0_131\\jre\\lib\\jfr.jar;D:\\Program Files\\Java\\jdk1.8.0_131\\jre\\lib\\jfxswt.jar;D:\\Program Files\\Java\\jdk1.8.0_131\\jre\\lib\\jsse.jar;D:\\Program Files\\Java\\jdk1.8.0_131\\jre\\lib\\management-agent.jar;D:\\Program Files\\Java\\jdk1.8.0_131\\jre\\lib\\plugin.jar;D:\\Program Files\\Java\\jdk1.8.0_131\\jre\\lib\\resources.jar;D:\\Program Files\\Java\\jdk1.8.0_131\\jre\\lib\\rt.jar;E:\\coding\\java1.0\\target\\classes;E:\\coding\\java1.0\\src\\main\\java\\lib\\commons-io-2.6.jar;C:\\Users\\86157\\.m2\\repository\\org\\projectlombok\\lombok\\1.18.24\\lombok-1.18.24.jar;C:\\Users\\86157\\.m2\\repository\\junit\\junit\\4.12\\junit-4.12.jar;C:\\Users\\86157\\.m2\\repository\\org\\hamcrest\\hamcrest-core\\1.3\\hamcrest-core-1.3.jar\" com.fh.thread.locks.spinlock.ABATest\n" +
                "A1 = >1\n" +
                "B1 = >1\n" +
                "b2 = >true\n" +
                "A2 = >false\n" +
                "b2 = >值:6;版本号:2\n" +
                "A2 = >值:6;版本号:2\n" +
                "A3 = >false\n" +
                "A3 = >值:6;版本号:2\n" +
                "\n" +
                "Process finished with exit code 0\n为2】");
        System.out.println(atomicInteger.compareAndSet(1, 2));
        System.out.println(atomicInteger.get());
        System.out.println("【2、中间偷偷把2更新为原来的值1】");
        System.out.println(atomicInteger.compareAndSet(2, 1));
        System.out.println(atomicInteger.get());
        System.out.println("【3、因为第二步,把新值又更新为原来的值,所以此次以为原来的值没有更改过】");
        System.out.println(atomicInteger.compareAndSet(1, 11));
        System.out.println(atomicInteger.get());
    }
}

 

自定义AtomicXXX

package com.fh.thread.locks.spinlock;

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

public class SpinLockTest {
    public static void main(String[] args) {
        SpinLock spinLock = new SpinLock();
        new Thread(()->{
            try {
                spinLock.lock();
                TimeUnit.SECONDS.sleep(3);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }finally {
                spinLock.unlock();
            }
        },"t1").start();
        new Thread(()->{
            try {
                spinLock.lock();
                TimeUnit.SECONDS.sleep(3);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }finally {
                spinLock.unlock();
            }
        },"t2").start();
    }
}
class SpinLock{
    private AtomicReference<Thread> atomicReference = new AtomicReference<>();
    public void lock(){
        Thread thread = Thread.currentThread();
        System.out.println(thread.getName()+"加锁");
        while (!atomicReference.compareAndSet(null,thread)){
            try {
                TimeUnit.SECONDS.sleep(2);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println(thread.getName()+"自旋吧。。。");
        }
    }
    public void unlock(){
        Thread thread = Thread.currentThread();
        System.out.println(thread.getName()+"解锁");
        atomicReference.compareAndSet(thread,null);
    }
}

 

 

死锁

 

public class DeadLockTest {
    public static void main(String[] args) {
        String lockA = "lockA";
        String lockB = "lockB";
        new Thread(new MyThread(lockA,lockB),"1线程").start();
        new Thread(new MyThread(lockB,lockA),"2线程").start();
    }
}
class MyThread implements Runnable{
    private String lock1;
    private String lock2;

    public MyThread(String lock1, String lock2) {
        this.lock1 = lock1;
        this.lock2 = lock2;
    }

    @Override
    public void run() {
        synchronized (lock1){
            //lockA想拿B
            System.out.println(Thread.currentThread().getName()+ lock1 + "=> get" + lock2);
            try {
                TimeUnit.SECONDS.sleep(3);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            synchronized (lock2){
                //B想拿A
                System.out.println(Thread.currentThread().getName() + lock2 + "=> get" + lock1);
            }
        }
    }
}

 

 死锁问题排查

 

乐观锁

 CAS是乐观锁的技术实现

 

悲观锁

  它总是会假设当前情况是最坏的情况,在每次去拿数据的时候,都会认为数据会被别人改变,因此在每次进行拿数据操作的时候都会加锁,如此一来,如果此时有别人也来拿这个数据的时候就会阻塞知道它拿到锁。在Java中,Synchronized和ReentrantLock等独占锁的实现机制就是基于悲观锁思想。在数据库中也经常用到这种锁机制,如行锁,表锁,读写锁等,都是在操作之前先上锁,保证共享资源只能给一个操作(一个线程)使用。

  由于悲观锁的频繁加锁,因此导致了一些问题的出现:比如在多线程竞争下,频繁加锁、释放锁导致频繁的上下文切换和调度延时,一个线程持有锁会导致其他线程进入阻塞状态,从而引起性能问题。

posted @ 2022-06-21 12:26  禁止摆烂  阅读(50)  评论(0)    收藏  举报