synchronized

synchronized特性

synchronized使用

synchornized锁机制



1.synchronized的特性

  1. 根据六大锁策略,synchronized刚开始是轻量级锁,后面可能会升级为重量级锁;
  2. 所以即是轻量级锁也是重量级锁;
  3. 所以既是自旋锁也是挂起等待锁,轻量级锁由自旋方式实现,重量级锁由系统调用API,挂起等待锁实现;
  4. 是一种非公平锁;
  5. 是一种可重入锁;
  6. 是互斥锁,不是可读锁;

2.synchronized使用

synchronized是一个保证线程安全的关键字,常用来修饰方法和代码块,确保同一个时刻只有一个线程被修饰的代码在执行,防止数据被多个线程获取修改带来的线程不安全;

使用sunchronized需要指定一个变量或者对象作为标志,意在说明两个或多个代码块或者方法竞争的是同意一把锁,只有有竞争才有锁存在的意义;

1.一般用法(多线程)
public class Example {

    public static void main(String[] args) throws InterruptedException {
        Object lock=new Object();
        Thread t1=new Thread(new Runnable() {
            @Override
            public void run() {
                synchronized(lock){
                    System.out.println("线程1");
                    try {
                        Thread.sleep(10000);
                    } catch (InterruptedException e) {
                        throw new RuntimeException(e);
                    }
                }
            }
        });
        Thread t2=new Thread(new Runnable() {
            @Override
            public void run() {
                synchronized(lock){
                    System.out.println("线程2");
                    try {
                        Thread.sleep(10000);
                    } catch (InterruptedException e) {
                        throw new RuntimeException(e);
                    }
                }
            }
        });
        t1.start();
        t2.start();
        t1.join();
        t2.join();
    }
}

由于两个线程的方法竞争的是同意一把锁(一样的标志对象),所以无论哪个线程先执行,只有另一个线程synchronized代码块完全执行完,另一个线程获取到锁才能继续执行;

2.用于代码块
2.1 锁任意对象
public class test1 {
    public static void main(String[] args) {
        Object lock=new Object();
        Thread t=new Thread(new Runnable() {
            @Override
            public void run() {
                synchronized (lock){
                    
                }
            }
        });
    }
}
2.2 锁当前对象
public class test2 {
    public void example(){
        synchronized(this){//this指的是调用当前方法的对象
            
        }
    }
}

由于方法种只有一个synchronized一个代码块,所以可以将synchronized夹在public之后

public class test2 {
    public synchronized void example(){
        
    }
}
拓展
public class test2 {
    public synchronized void example1(){

    }

    public synchronized void example2(){

    }
}

由于代码中的两个方法,锁的都是调用该方法的对象,所以同一个线程同一个时刻只能执行一个方法,称之为同步方法

3.用于方法
3.1 直接用于普通方法 锁:调用该方法的对象(test2的实例化对象)
public class test2 {
    public synchronized void example1() {

    }
}
3.2直接用于静态方法 锁:test2的类对象
public class test2 {
    public synchronized static void example1() {

    }
}
wait()

一般配合synchronized使用,lock.wait(),执行之后让该线程挂起,进入等待队列并释放锁,等待被唤醒;

notify()/notifyAll()

lock.notify()唤醒该对象挂起等待队列的任意一个的线程,并尝试让它去获取锁;

lock.notifyAll()唤醒该对象挂起等待队列的所有线程,并让他们去竞争锁,没拿到锁的重新进入等待队列;

3.synchronized锁机制

synchronized加锁的过程一般分为四步,无锁->偏向锁->轻量级锁->重量级锁

偏向锁

第一个获取该锁的线程,进入偏向锁状态

偏向锁并不是真的给该线程加锁,只是加一个偏向锁的标记,记录该锁属于哪个线程;如果后续没有其他线程尝试获取该锁,就一直是偏向锁状态,不消耗加锁的开销;如果有其他线程尝试加锁,由于该锁已经记录属于哪个线程,这个时候锁就升级成为轻量级锁;

轻量级锁

如果由其他线程的锁竞争,就会取消偏向锁状态,进入轻量级锁;

轻量级锁一般用自旋锁方式实现,通过CAS机制实现;

  • 检查该线程是否获得该锁
  • 获得锁,加锁成功
  • 没有获得锁,加锁失败

并不会一直循环检查,到了一定时间/次数还没有获得锁,就会变成重量级锁,所以也成为自适应的轻量级锁;

重量级锁

升级成为轻量级锁之后还没有获得锁,就会继续升级成为重量级锁;

重量级实际就是进入内核,调用内核提供的mutex;

  • 进入内核,进行加锁;
  • 判断该锁是否被占用;
  • 锁没有被占用,加锁成功,返回用户态;
  • 锁被占用,加锁失败,该线程进入等待队列,等待被唤醒;
  • 等待该锁被释放,操作系统想起唤醒该线程,该线程才去尝试获取锁;

synchronized锁优化

具体可以参考我的另一篇博客,锁策略,CAS和synchronized的锁优化

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

a添砖Java

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

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

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

打赏作者

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

抵扣说明:

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

余额充值