synchronized【多线程与高并发第二讲】

synchronized【多线程与高并发第二讲】,第1张

synchronized【多线程与高并发第二讲】

synchronized【多线程与高并发第二讲】

synchronized锁

锁的理解业务案例synchronized可重入synchronized方法异常理论知识

synchronized锁 锁的理解

在下面代码中锁的是o,锁的底层。任何人执行都得先拿到o这把锁,锁定是锁定的某个对象
synchronized是具备原子性的

    private final Object o = new Object();

    public void m() {
        synchronized (o) {
            count--;
            System.out.println(Thread.currentThread().getName() + "count=" + count);
        }
    }

以下代码中m_01和m_02以及m_03锁定是等值的

    public void m_01() {
        synchronized (this) {//m_01和m_02是等值的
            count--;
            System.out.println(Thread.currentThread().getName() + "count=" + count);
        }
    }

    public synchronized void m_02() {//锁的是T01.class对象
        count--;
        System.out.println(Thread.currentThread().getName() + "count=" + count);
    }
    
    public void m_03() {//锁的是T01.class对象
        synchronized (T01.class) {
            count--;
            System.out.println(Thread.currentThread().getName() + "count=" + count);
        }
    }
业务案例

设置值的时候采用synchronized,获取的时候不采用加锁的方式

//设置加锁
    public synchronized void set(String name, BigDecimal balance) {
        this.name = name;
        try {
            Thread.sleep(2000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        this.balance = balance;
    }
//获取不加锁
    public  BigDecimal getBalance(String name) {
        return this.balance;
    }


    //容易产生脏读
    public static void main(String[] args) {
        T03 t03 = new T03();
        new Thread(() -> t03.set("zhangsan", BigDecimal.valueOf(100))).start();
        try {
            TimeUnit.SECONDS.sleep(1);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("第一次读取 zhangsan的金额为:" + t03.getBalance("zhangsan"));
        try {
            TimeUnit.SECONDS.sleep(2);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("第二次读取 zhangsan的金额为:" + t03.getBalance("zhangsan"));
    }

一个具有注脚的文本。1

synchronized可重入

synchronized是一把可重入锁。简单理解:调用m1获取一把锁,调用m2的时候发现是同一个线程,同样有锁,锁就是可重入的。
如果不可重入的话,导致第二个线程也需要获取锁。特别是涉及到继承的时候,如果子类继承父类。子类获取锁调用父类加锁的方法。会导致一直死锁。

synchronized void m1() {
        System.out.println("m1 start");
        m2();
        System.out.println("m1 end");
    }

    synchronized void m2() {
        System.out.println("m2 start");
    }

    public static void main(String[] args) {
        new T04().m1();
    }
synchronized方法异常

如果程序出现异常,锁会被释放、要是不想释放、这里可以让catch、继续执行。
如果抛出异常。会导致其他线程访问到上一个线程的数据。

int count = 1;

    synchronized void m1() {
        //try {
        for (int i = 0; i < 10; i++) {
            count++;
            System.out.println("count数据=" + count);
            if (i == 9) {
                int j = count / 0;
            }
        }
        count = 1;
        //} catch (Exception e) {
        //    count = 1;
        //    e.printStackTrace();
        //}
    }
    public static void main(String[] args) {
        T05 t05 = new T05();
        new Thread(() -> {
            System.out.println("第一线程打印数据");
            t05.m1();
        }).start();
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        new Thread(() -> {
            System.out.println("第二线程打印数据");
            t05.m1();
        }).start();
    }

理论知识

synchronized的底层实现
1.JDK早期、重量级,只要加锁都会去找 *** 作系统获取锁。
2.synchronized升级之后:markword 偏向锁(只有一个线程的时候,会偏向该线程)多个线程之后升级为自旋锁(旋10次之后)升级为重量锁去 *** 作系统获取锁
3.锁只能升级。不能降级
4.什么时候使用自旋锁,占用CPU,不访问 *** 作系统,加锁和解锁的动作下的
5.自旋锁用户态:不使用内核态。
6.执行时间短(加锁代码),线程数少,使用自旋锁
7.执行时间长、线程数多,用系统锁(Syn)
8.不能用String常量 Integer Long做synchronized因为会出现不同的方法使用该常量的。导致使用该常量就多次加锁,出现死锁等情况。


  1. 读取尽量不使用synchronized,毕竟使用加锁效率会降低10倍以上的。 ↩︎

欢迎分享,转载请注明来源:内存溢出

原文地址: https://outofmemory.cn/zaji/5708211.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-12-17
下一篇 2022-12-17

发表评论

登录后才能评论

评论列表(0条)

保存