JavaEE初阶(四)-synchronized关键字-监视器锁

目录

目录

1 synchronized的特性

1.1互斥特性

1.2 刷新内存

1.3 可重入

2 synchronized使用示例

2.1 修饰普通方法和静态方法

2.2 修饰代码块:明确指定锁那个对象

3 Java标准库中的线程安全类和不安全类


1 synchronized的特性

1.1互斥特性

synchronized会起到互斥效果,synchronized的底层是使用操作系统的mutex lock来实现的。当某个线程执行到某个对象的synchronized中时,其他线程如果也执行到同一个对象synchronized就会阻塞等待。

.进入synchronized修饰的代码块,相当于加锁。

.退出synchronized修饰的代码块,相当于解锁。

比如下列代码:

synchronized void increase(){
    count++;
}

在代码第一行进入了increase()方法。相当于完成了加锁操作。在执行到最后一个大括号之后,相当于针对当前所创建的对象进行了解锁操作。

synchronized用的锁是存储在Java对象里面的。

当一个线程上了锁之后,那么其他线程就只能等待这个线程释放锁。其他的线程也会尝试加锁,但是加不上,因此这种现象就叫做阻塞等待现象。虽然其他线程都会等待这个线程释放锁,但是当其释放了锁之后,其余线程也会争抢这把锁,不遵循先来后到的原则。

1.2 刷新内存

suychronized的工作过程:

. 获得互斥锁

. 从主内存拷贝变量的最新副本到工作内存

. 执行代码

. 将更改后的共享变量的值刷新到主内存

. 释放互斥锁

1.3 可重入

synchronized 同步块对同一条线程来说是可重入的,不会出现把自己锁死的情况。

如下两段代码所示:

这是不加synchronized的锁,会出现锁死现象。

//第一次加锁成功
lock();
//第二次阻塞等待
lock();

这是加了synchronized的锁,因为可重入,所以并不会锁死,在该代码中的synchronized加锁对象是该类中的this,因为是同一把锁。

static class Counter{
    public int count=0;
    
    synchronized void increase(){
        count++;
    }

    synchronized void increase2(){
        increase();
    }
}

在可重入锁内部包含了线程持有者和计数器两个信息

. 如果某个线程想要加锁的时候发现锁已经被人占用,如果该人正好是自己,那么仍然可以获取到锁,并让计数器自增。

. 解锁的时候,当计数器减为0之后,才会真正的释放锁。这样别的线程才可以获取到这把锁。

2 synchronized使用示例

synchronized本质上是要修改指定对象的对象头,从使用的角度来看,synchronized也需要搭配一个具体的对象来使用。

2.1 修饰普通方法和静态方法

直接修饰普通方法:锁synchronizedDemo对象

public class synchronizedDemo{
    public synchronized void method(){
    }
}

 修饰静态方法:锁的synchronizedDemo类的对象

public class SynchronizedDemo {
    public synchronized static void method() {
   }
}

这么说可能能简洁明了一点,因为静态成员在创建不同的对象时,只创建一次,因此被static所修饰的变量或者方法是所有实例所公用的。因此在使用synchronized锁静态方法时(因为静态方法是和类直接关联的),无论该类有多少个实例,都会来竞争这个锁资源。但是非普通的方法就不存在不同实例竞争锁资源的情况。

2.2 修饰代码块:明确指定锁那个对象

锁当前对象:

public class SynchronizedDemo {
    public void method() {
        synchronized (this) {
            
       }
   }
}

锁类对象:

public class synchronizedDemo{
    public void method(){
        synchronized(synchronizedDemo.class);
    }
}

第一段代码使用当前实例对象作为锁对象,意味着每一个实例对象都有自己的锁资源,不同实例之间的锁是独立的,不会相互干扰。

第二段代码使用类对象作为锁对象,意味着当多个线程访问该类的不同实例时,他们会竞争同一个锁资源。

3 Java标准库中的线程安全类和不安全类

安全不安全

Vector

HashTable

ConcurrentHashMap

StringBuffer

ArrayList

LinkedList

HashMap

TreeMap

HashSet

TreeSet

StringBuilder

StringBuffer的核心方法带有synchronized。还有的类不涉及到加锁,是因为没有涉及到修改,比如String 。

  • 9
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值