每日一记–synchronized关键字

synchronized关键字(隐式的获取和释放锁)

作用于静态方法:

对象锁给对象加锁(可以理解为这个对象的内存上锁,注意:只是这块内存,其他同类对象都会有各自的内存锁)这时候在其他一个以上线程中执行该对象的这个同步方法(注意:是该对象)就会产生互斥)

作用于静态方法:

类锁:相当于在类上枷锁(*.class位于代码区,静态方法位于静态区域,这个类产生的对象公用这个静态方法,所以这块内存,N个对象来竞争),这时候,只要是这个类产生的对象,在调用这个静态方法时都会产生互斥

对象锁与类锁区别:主要就在于内存区域不同 对象锁只作用与同类的单个对象的内存区域 类锁则作用于同类的所有对象的内存区域

Java线程内存模型:每个线程都用拥有自己的栈、堆内存共享、如下图所示。锁是线程间内存和信息沟通的载体。img

Java中为了保证每个线程中的原子操作,引入了内置锁或者称监视器锁,其中,每个Java对象都可以作为实现锁的对象。

synchronized关键字修饰的代码块被称为同步代码块 ,线程进入同步代码块自动获取内置锁,退出同步代码块则释放锁,不需要调用者考虑它的创建以及消除而别的线程此时无法获得这把锁,就无法调用这个方法。一个线程想要获得这个锁只能等上一个线程执行结束这个方法将锁释放,下一个线程才能有机会调用这个方法获得该对象的锁(即synchronized关键字可以获得内置锁,同一时间只允许一个线程获得某个锁)。

java的每个对象都有一个锁,不需要显示地去创建。

java的内置锁:每个java对象都可以用做一个实现同步的锁,这些锁称为内置锁线程进入同步代码块或方法的时候会自动获得该锁,在退出同步代码块或方法时会释放该锁。获得内置锁的唯一途径就是进入这个锁的保护的同步代码块或方法

java内置锁是一个互斥锁,这就意味着同一时间最多只有一个线程能够获得该锁,当线程A尝试去获得线程B持有的内置锁时,线程A必须等待或者阻塞,直到线程B释放这个锁,如果B线程不释放这个锁,那么A线程将永远等待下去。

1.同步方法(粗粒度锁)

即有synchronized关键字修饰的方法。

由于java中每个对象都有一个内置锁,当使用此关键字修饰方法时,内置锁会保护整个方法。在调用该方法前,需要获得内置锁,否则就处于阻塞状态

public synchronized void save(){
方法体
}

2.同步代码块(细粒度锁)

即有synchronized关键字修饰的语句块。

被该关键字修饰的语句块会被自动加上内置锁,从而实现同步。

synchronized(object){ 
代码;
}

注:同步是一种高开销的操作,因此应该尽量减少同步的内容。 通常没有必要同步整个方法,使用synchronized代码块同步关键代码即可。 同步会影响一定的多线程性能

synchronized的缺陷:当某个线程进入同步方法获得对象锁,那么其他线程访问这里对象的同步方法时,必须等待或者阻塞,这对高并发的系统是致命的,这很容易导致系统的崩溃。如果某个线程在同步方法里面发生了死循环,那么它就永远不会释放这个对象锁,那么其他线程就要永远的等待。这是一个致命的问题。