Synchronized同步锁

1. 锁介绍

在Java中每个对象或类都可以当做锁使用,这些锁称为内置锁

Java中内置锁都是互斥锁。也就是说一个线程获取到锁,其他线程必须等待或阻塞。 如果占用锁的线程不释放锁,其他线程将一直等待下去。锁在同一时刻,只能被一个线程持有

如果锁是作用于对象,称对象锁。如果锁作用整个类称为类锁

2. synchronized介绍

  1. synchronized关键字是锁的一种实现。
  2. synchronized的加锁和解锁过程不需要程序员手动控制 ,只要执行到synchronized作用范围会自动加锁(获取锁/持有锁),执行完成后会自动解锁(释放锁)加锁的范围中代码出现异常,自动解锁。
  3. synchronized具有可见性、有序性和原子性。
  4. synchronized分多种情况:
  • 修饰实例方法(对象锁)
  • 修饰静态方法(类锁)
  • 修饰代码块(对象锁、类锁)

3. 修饰实例方法

 先创建几个线程

        Test01 test01 = new Test01();//创建一次对象
        for (int i = 0; i < 3; i++) {
        /* 每一个线程都会创建一个新对象,不同对象调用加锁的方法,锁失效 */
            //Test01 test01 = new Test01(); //创建三次对象
            new Thread(new Runnable() {
                @Override
                public void run() {
                    test01.test3();
                }
            }).start();

            Thread.sleep(3000);
            System.out.println(a);
        }

锁类型:使用synchronized修饰实例方法时为对象锁。

锁范围:锁的范围是加锁的方法。

锁生效:必须为同一个对象调用该方法该锁才有作用。

    /*
    加锁:执行到加锁的方法,自动加锁
    释放锁:执行完加锁的方法,自动解锁,出现异常自动解锁
    锁范围:加锁的方法
    锁类型:对象锁(同一个对象生效)多个线程争夺同一个对象锁
    锁失效:多个对象失效
     */
    public synchronized void test1(){//实例方法
        for (int i = 0; i < 10000; i++) {
            a++;
        }
    }

4. 修饰静态方法

锁类型:使用synchronized修饰静态方法时为类锁。

锁范围:锁的范围是加锁的方法。

锁生效:该类所有的对象调用加锁方法,锁都生效 。必须为同一个类调用该方法锁才有作用。

    /*
    加锁:执行到加锁的方法,自动加锁
    释放锁:执行完加锁的方法,自动解锁,出现异常自动解锁
    锁范围:加锁的方法
    锁类型:类锁(同一个类生效,和对象无关)多个线程争夺同一个类锁
     */
    public static synchronized void teat2(){
        for (int i = 0; i < 10000; i++) {
            a++;
        }
    }

5. 修饰代码块

锁代码块是非常重要的地方。添加锁的类型是Object类型。

使用synchronized修饰的代码块语法格式为:

synchronized(锁){

        // 内容

}

5.1 锁为固定值

由于固定值属于类且值固定不变,所有的对象调用加锁的代码块,都会争夺锁资源,属于类锁

    /*
    加锁:执行到加锁的方法,自动加锁
    释放锁:执行完加锁的方法,自动解锁,出现异常自动解锁
    锁范围:加锁的代码块
    锁类型:类锁(同一个固定值)
    锁失效:多个值
     */
    final String LOCK = "锁";//固定值
    public void test3(){
        synchronized (LOCK){
            for (int i = 0; i < 10000; i++) {
                a++;
            }
        }
    }
5.2 锁为不同内容
    public void test4(String s){//s为每个线程的名字,线程名字不同
        synchronized (s){//锁不相同,相当于没有加锁,锁资源不需要竞争
            for (int i = 0; i < 10000; i++) {
                a++;
            }
        }
    }
5.3 锁为this
5.3.1 同一个对象调用加锁方法时:

如果是同一个对象调用synchronized所在方法时,this代表的都是一个对象。this就相当于固定值。所以可以保证结果正确性,属于对象锁。

5.3.2 不同对象调用加锁方法时:

如果不是同一个对象调用synchronized所在方法时,this所代表的对象就不同。相当于锁为不同内容时,锁失效。

    /*
    加锁:执行到加锁的方法,自动加锁
    释放锁:执行完加锁的方法,自动解锁,出现异常自动解锁
    锁范围:加锁的代码块
    锁类型:对象锁(同一个对象)
    锁失效:多个对象
     */
    public void test5(){
        synchronized (this){//this表示当前对象
            for (int i = 0; i < 10000; i++) {
                a++;
            }
        }
    }
5.4 锁为class

锁为Class时,是一个标准的类锁,所有的对象调用加锁的代码块都生效。

    /*
    加锁:执行到加锁的方法,自动加锁
    释放锁:执行完加锁的方法,自动解锁,出现异常自动解锁
    锁范围:加锁的代码块
    锁类型:类锁(同一个类对象生效)
     */
    public void test6(){
        synchronized (Test01.class){//Test01.class类对象
            for (int i = 0; i < 10000; i++) {
                a++;
            }
        }
    }

6. 对象锁和类锁

当synchronized修饰静态方法或代码块参数为Class时或代码块参数为固定值,锁为类锁,作用整个类。同一个类使用,锁生效。

当synchronized修饰实例方法或代码块参数为this时,为对象锁,只对当前对象有效。

多个对象使用时,锁生效,使用类锁。

同一对象使用时,锁生效,使用对象锁。

7. 可重入锁

某个线程已经获得了某个锁,允许再次获得锁,就是可重入锁。如果不允许再次获得锁就称为不可重入锁。

synchronized为可重入锁。但可重入锁不仅仅只有synchronized。ReentrantLock也是可重入锁。

    Test02 test02 = new Test02();
    new Thread(new Runnable() {
        @Override
        public void run() {
            test02.test1();
        }
    }).start();

    Thread.sleep(1000);

    public synchronized void test1(){//可重入锁
        System.out.println("t1");
        //此时还没释放锁
        test2();//再次申请锁资源
    }

    public synchronized void test2(){
        System.out.println("t2");
    }
7.2 可重入锁底层原理

可重入锁底层原理就是计数器。

当一个线程第一次持有某个锁时会由monitor(监控器)对持有锁的数量加1,当这个线程再次需要碰到这个锁时,如果是可重入锁就对持有锁数量再次加1(如果是不可重入锁,发现持有锁为1了,就不允许多次持有这个锁了,阻塞),当释放锁时对持有锁数量减1,直到减为0,表示完全释放了这个锁。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值