signed

QiShunwang

“诚信为本、客户至上”

多线程高阶一——锁策略

2021/6/3 17:07:16   来源:

ThreadLocal缺点:
1.不可继承性(子线程不能读取父线程的变量)
2.脏数据(ThreadPool线程复用相关的额静态变量)
3.内存溢出
ThreadPool(长生命周期)->Thread->ThreadLocal ->map->Entry-> key,value(强引用)

常见锁策略

乐观锁:它认为一般情况下不会发生冲突,所以只有在进行数据更新的时候,才会检测并发冲突,如果没有冲突则执行修改,如果有冲突则返回失败。

CAS
V(内存值)
A(旧值)
B(新值)

在这里插入图片描述
在这里插入图片描述

乐观锁的实现Atomic*

package ThreadDemo0527;

import java.util.concurrent.atomic.AtomicInteger;

public class ThreadDemo02 {
    private  static AtomicInteger count=new AtomicInteger(0);
    private static final int MAXSIZE=100000;

    public static void main(String[] args) throws InterruptedException {
       Thread t1=new Thread(new Runnable() {
            @Override
            public void run() {
                for (int i = 0; i <MAXSIZE ; i++) {
                    count.getAndIncrement();
                }
            }
        });
        t1.start();

        Thread t2=new Thread(new Runnable() {
            @Override
            public void run() {
                for (int i = 0; i <MAXSIZE ; i++) {
                    count.getAndDecrement();
                }
            }
        });
        t2.start();

        t1.join();
        t2.join();
        System.out.println("最终结果"+count);
//        AtomicInteger count=new AtomicInteger(0);//int count=0;
//        count.getAndIncrement();//i++
//        count.incrementAndGet();//++i

    }
}

在这里插入图片描述

在这里插入图片描述

乐观锁性能比较高。
CAS的缺点: ABA问题->AtomicInteger存在ABA问题(A旧值,B新值)

/**
 * ABA问题演示
 */
package ThreadDemo0527;

import java.util.concurrent.atomic.AtomicReference;

public class ThreadDemo03 {
    private static AtomicReference money =
            new AtomicReference(100);

    public static void main(String[] args) throws InterruptedException {

        // 转账线程 1(-100)
        Thread t1 = new Thread(new Runnable() {
            @Override
            public void run() {
                // 转账
                boolean result = money.compareAndSet(100, 0);
                System.out.println("第一次转账(-100):" + result);
            }
        });
        t1.start();

        t1.join();

        // 转入 100 元
        Thread t3 = new Thread(new Runnable() {
            @Override
            public void run() {
                // +100
                boolean result = money.compareAndSet(0, 100);
                System.out.println("转入 100 元:" + result);
            }
        });
        t3.start();

        t3.join();

        // 转账线程 2(-100)
        Thread t2 = new Thread(new Runnable() {
            @Override
            public void run() {
                // 转账
                boolean result = money.compareAndSet(100, 0);
                System.out.println("第二次转账(-100):" + result);
            }
        });
        t2.start();


    }
}

在这里插入图片描述

ABA 统一解决方案
增加版本号,每次修改之后更新版本号
在这里插入图片描述

/**
 * 解决ABA问题
 */
package ThreadDemo0527;

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

public class ThreadDemo04 {
    private static AtomicStampedReference money =
            new AtomicStampedReference(100,1);

    public static void main(String[] args) throws InterruptedException {

        // 转账线程 1(-100)
        Thread t1 = new Thread(new Runnable() {
            @Override
            public void run() {
                // 转账
                boolean result = money.compareAndSet(100,0,1,2);
                System.out.println("第一次转账(-100):" + result);
            }
        });
        t1.start();

        t1.join();

        // 转入 100 元
        Thread t3 = new Thread(new Runnable() {
            @Override
            public void run() {
                // +100
                boolean result = money.compareAndSet(0,100,2,3);
                System.out.println("转入 100 元:" + result);
            }
        });
        t3.start();

        t3.join();

        // 转账线程 2(-100)
        Thread t2 = new Thread(new Runnable() {
            @Override
            public void run() {
                // 转账
                boolean result = money.compareAndSet(100,0,1,2);
                System.out.println("第二次转账(-100):" + result);
            }
        });
        t2.start();


    }
}

Integer 高速缓存 -128——127
在这里插入图片描述
解决方案:调整Integer高速缓存的边界值

悲观锁:它认为通常情况下会出现并发冲突,所以在一开始就会加锁。

synchronized是悲观锁

共享锁、非共享锁

共享锁:一把锁可以被多个程序拥有,这就叫共享锁

读写锁中的读锁就是共享锁

读写锁:就是把一个锁分成连个,一个用于读数据的锁,另一把锁叫做写锁。读锁是可以被多个线程同时拥有的,而写锁只能被一个线程拥有。

读写锁的具体实现:ReentrantReadWriteLock
优势:锁的力度更加的小,心梗也更高

非共享锁:一把锁只能被一个线程拥有,这就叫非共享锁

注意:读写锁中的读锁和写锁是互斥的(防止同时读写所产生的脏数据)

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

在这里插入图片描述

可重入锁

package ThreadDemo0527;

public class ThreadDemo06 {
    // 创建锁
    private static Object lock = new Object();

    public static void main(String[] args) {
        // 第一次进入锁
        synchronized (lock) {
            System.out.println("第一次进入锁");
            synchronized (lock) {
                System.out.println("第二次进入锁");
            }
        }
    }
}

在这里插入图片描述

在这里插入图片描述