一、同步机制关键字synchronized
最常用的同步机制就是synchronized关键字,能够作用于对象、函数、Class。每个对象都只有一个锁,谁能够拿到这个锁谁就有访问权限。
当synchronized作用于函数时,实际上锁的也是对象,锁定的对象就是该函数所在类的对象。而synchronized作用于class时则是锁的当前这个Class对象。故Synchronized 锁存在方法锁、对象锁、类锁的概念。
代码如下:当synchronized作用于函数时,实际上锁的也是对象,锁定的对象就是该函数所在类的对象。而synchronized作用于class时则是锁的当前这个Class对象。故Synchronized 锁存在方法锁、对象锁、类锁的概念。
public class SynchronizedTest { /** * 同步锁方法-->锁对象 * 是防止其他线程访问同一个对象中synchronized代码块或函数 */ public synchronized void synchronizedMethod(int data) throws InterruptedException { //代码 } /** * 同步锁块-->锁对象 * 是防止其他线程访问同一个对象中synchronized代码块或函数 */ public void synchronizedThisMethod() throws InterruptedException { synchronized (this) { //代码 } } /** * 同步锁class对象-->锁Class对象 * 是防止多个线程同时访问添加synchronized锁的代码块 */ public void synchronizedClassMethod() { synchronized (SynchronizedTest.class) { //代码 } } /** * 同步锁静态方法-->锁Class对象 * 是防止多个线程同时访问添加了synchronized锁的代码块 */ public synchronized static void synchronizedStaticMethod() { //代码 } }
Synchronized 方法锁:
方法锁是指使用Synchronized关键字修饰声明的方法,其实方法锁也就是对象锁的一种写法形式,目的是控制对类成员变量 的访问。
每个类实例都对应一把锁,所以每个Synchronized方法都必须通过类实例调用,Synchronized 方法一旦执行就会占用该锁,此时若有其他线程A访问该方法,则线程A就会处于阻塞状态直到方法锁释放,线程A才可获取该锁,从而重新进入可执行状态。
这种机制的好处确保每一个类实例中的Synchronized方法在同一时刻只能有一个处于可执行状态,从而有效的避免了访问冲突。
l例子:每个类实例都对应一把锁,所以每个Synchronized方法都必须通过类实例调用,Synchronized 方法一旦执行就会占用该锁,此时若有其他线程A访问该方法,则线程A就会处于阻塞状态直到方法锁释放,线程A才可获取该锁,从而重新进入可执行状态。
这种机制的好处确保每一个类实例中的Synchronized方法在同一时刻只能有一个处于可执行状态,从而有效的避免了访问冲突。
周杰伦演唱会预售10000张门票,共5个售票窗口,若我们将售票的方法定义同步的,则每个窗口会卖出5张票后才允许其他窗口售票.
代码:
public class SaleDemo { //售票总量 static int saleCount = 10000; /** * 定以售票窗口同步售票方法 */ public synchronized void saleWindows() { //每个售票窗口售票数量 int singleWindowSaleCount = 5; for (int index = 0; index < singleWindowSaleCount; index++) { saleCount--; System.out.println("当前窗口:" + Thread.currentThread().getName() + " | " + "当前剩余:" + saleCount); } } public static void main(String[] arg) { //声明一个类的实例 final SaleDemo saleDemo = new SaleDemo(); //我们假设开设了5个售票窗口 for (int index = 0; index < 5; index++) { new Thread() { @Override public void run() { saleDemo.saleWindows(); } }.start(); } } }
对象锁 有两种表现形式:
- 锁方法
public synchronized void saleWindows() { //每个售票窗口售票数量 int singleWindowSaleCount = 5; for (int index = 0; index < singleWindowSaleCount; index++) { saleCount--; System.out.println("当前窗口:" + Thread.currentThread().getName() + " | " + "当前剩余:" + saleCount); } }
- 锁代码块
public void saleWindows() { //每个售票窗口售票数量 int singleWindowSaleCount = 5; synchronized (this) { for (int index = 0; index < singleWindowSaleCount; index++) { saleCount--; System.out.println("当前窗口:" + Thread.currentThread().getName() + " | " + "当前剩余:" + saleCount); } } }
所以我们上面介绍的方法锁也是对象锁的一种.
当一个类中存在Synchronized Method 或 Synchronized Block时,当类实例对象调用Synchronized Method 或 Synchronized Blocks时必须先获取对象锁,若此对象此时被其他调用者占用,则需要等待对象所被释放 。
这里需要讲解一下的是:JAVA中都包含一个互斥锁,这个锁由JVM自动获取和释放。
当一个类中存在Synchronized Method 或 Synchronized Block时,当类实例对象调用Synchronized Method 或 Synchronized Blocks时必须先获取对象锁,若此对象此时被其他调用者占用,则需要等待对象所被释放 。
这里需要讲解一下的是:JAVA中都包含一个互斥锁,这个锁由JVM自动获取和释放。
Synchronized 类锁
Synchronized类锁同样具有两种表现形式:
- 静态方法锁
public static synchronized void saleWindows() { //每个售票窗口售票数量 int singleWindowSaleCount = 5; for (int index = 0; index < singleWindowSaleCount; index++) { saleCount--; System.out.println("当前窗口:" + Thread.currentThread().getName() + " | " + "当前剩余:" + saleCount); } }
- 代码块锁
public void saleWindows() { //每个售票窗口售票数量 int singleWindowSaleCount = 5; synchronized (SaleDemo.class) { for (int index = 0; index < singleWindowSaleCount; index++) { saleCount--; System.out.println("当前窗口:" + Thread.currentThread().getName() + " | " + "当前剩余:" + saleCount); } } }
一个Class类不论实例化多少次,其Class中包含的静态变量成员和静态方法在内存中只存在一份。所以一旦一个静态方法加了同步锁,此类中所有实例对象在调用此方法时共用同一把锁,即类锁
对象锁和类锁的区别
- 对象锁用来控制类实例方法之间的同步访问
- 类锁是用来控制静态方法之间的同步访问