一、同步机制关键字synchronized
最常用的同步机制就是synchronized关键字,能够作用于对象、函数、Class。每个对象都只有一个锁,谁能够拿到这个锁谁就有访问权限。
当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方法在同一时刻只能有一个处于可执行状态,从而有效的避免了访问冲突。
举个栗子吧:
周杰伦演唱会预售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();
}
}
}
运行结果
![](https://img.haomeiwen.com/i12592391/8f73398a0da985e2.png)
Synchronized 对象锁
首先我们需要了解的是对象锁 有两种表现形式
- 锁方法
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 类锁
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中包含的静态变量成员和静态方法在内存中只存在一份。所以一旦一个静态方法加了同步锁,此类中所有实例对象在调用此方法时共用同一把锁,即类锁
对象锁和类锁的区别
- 对象锁用来控制类实例方法之间的同步访问
- 类锁是用来控制静态方法之间的同步访问
网友评论