Java多线程笔记2

synchronized使用:
同步代码块
synchronized(this|任意一个Object子类对象|当前类.class) {

}

同步方法

修饰普通对象方法 锁当前对象this

修饰类的静态方法 锁当前类.class

保护的是什么?几个锁?
使用一把锁锁住了两个毫无关系的对象

如何保护毫无关系的资源?
使用多把锁锁住不同的资源

 

class Account {
    // 余额
    int sal;
    // 密码
    String password;
    // 余额资源的锁
    private Object salLock = new Object();
    // 密码资源的锁
    private Object passLock = new Object();
    public int getMoney() {
        synchorinzed(salLock) {}
    }

    public void setMoney() {
        synchorinzed(salLock) {}
    }

    public String getPassword() {
        synchorinzed(passLock) {}
    }
    
    public void setPassword() {
        synchorinzed(passLock) {}
    }
}

 

转账
A -> B 100
A -= 100;
B += 100;
如何保护有关联关系的对象:
使用同一把锁

public void zhuangzhang(Account target) {
    synchroinzed(Account.class) {
        this.sal -= 100;
        target.sal += 100;
    }
}

由于转账涉及两个账户间的sal操作,因此需要将两个账户同时锁定。
由于方法的synchrond只能锁一个对象,因此锁不住转账操作

 

这个时候要看synchronized底层实现

synchronized底层实现:
在使用synchronized时必须保证锁定对象必须为Object以及其子类对象。
synchronized使用的是JVM层级别的MonitorEnter与MonitorExit实现。

这两个指令都必须获取对象的同步监视器Monitor

对象锁Monitor机制

monitorenter:
检查obj对象的Monitor计数器值是否为0,为0表示此监视器还未被任意一个线程获取,此时线程可以进入同步代码块并且将Monitor值+1,将Monitor的持有线程标记为当前线程

当Monitor计数器值不为0且持有线程不是当前线程,表示Monitor已经被别的线程占用,当前线程只能阻塞等待。

当Monitor计数器值不为0但是持有线程恰好是当前线程,

monitorexit:
Monitor计数器值-1

可重入锁:
当执行MonitorEnter时。对象的Monitor计数器值不为0,但是持有线程恰好是当前线程,
此时将Monitor计数器值再次+1,当前线程继续进入同步方法或代码块,就好比上面第一个代码,我调用getMoney()方法的时候,getMoney()方法里面也可以调用getPassword()方法

 

CAS操作(无锁实现的同步-乐观锁)-自旋

class Test {
    int i = 0;
// 线程1
    synchronized(this) {
        i = 10;
    }
}    

CompareAndSwap(O,V,N)
O:当前线程存储的变量值 0
V:内存中该变量的具体值 10
N:希望修改后的变量值 10

当O==V时,此时表示还没有线程修改共享变量的值,此时可以成功的将内存中的值修改为N

当O!=V时,表示此时内存中的共享变量值已被其他线程修改,此时返回内存中的最新值V,再次尝试修改变量

线程挂起阻塞:车熄火
自旋:脚踩刹车,车不熄火

1.ABA问题:
解决ABA问题添加版本号

2.自旋在CPU上跑无用指令,会浪费CPU资源
自适应自旋
JVM尝试自旋一段时间,若在此时间内,线程成功获取到锁,再下次获取锁时,适当延长自旋时间。
若在此时间内,线程没有获取到锁,再下次获取锁时,适当缩短自旋时间。

3.公平性问题
处于阻塞态线程可能会一直无法获取到锁
Lock锁可以实现公平性,synchronized无法实现公平锁

偏向锁:JDK1.6之后默认synchronized
最乐观的锁:进入同步快或同步方法的始终是一个线程

当出现另一个线程也尝试获取锁(在不同时刻)时,偏向锁会升级为轻量级锁


轻量级锁
不同时刻有不同的线程尝试获取锁,"量黄灯策略"

同一时刻有不同线程尝试获取锁,会将偏向锁升级为重量锁

重量级锁
JDK1.6之前synchronized都是重量级锁,将线程阻塞挂起(JDK1.6自适应自旋)

锁只有升级过程没有降级过程

锁粗化

当出现多次连续的加锁与解锁过程,会将多次加减锁过程粗化为一次的加锁与解锁过程

 

死锁:
死锁产生条件:以下四种条件同时满足才会导致死锁
1.互斥
共享资源只能同时被一个线程占用
2.占用且等待
3.不可抢占
线程T1拿到了资源X的锁,其他线程不能抢占X锁
4.循环等待
线程T1拿到了资源X的锁,去申请Y的锁
线程T2拿到了资源Y的锁,去申请X的锁

 

posted @ 2019-06-10 23:44  码到成功hy  阅读(190)  评论(0编辑  收藏  举报
获取

hahah

name age option