一、synchronized关键字
-
- synchronized关键字提供一种锁的机制,确保共享变量的互斥访问,防止数据不一致
-
- synchronized关键字包括monitor enter和monitor exit两个JVM指令,能够保证在任何时候任何线程执行到monitor enter成功之前都必须从主内存中获取数据,而不是从缓存中,在monitor exit运行成功之后,共享变量被更新后的值必须存入主存
-
- synchronized的指令严格遵守java happens-before规则,一个monitor exit指令之前必定要有一个monitor enter
二、叫号例子
package safe;
/**
* @ClassName TicketWindowRunnable
* @Description TODO
* 1. synchronized关键字提供一种锁的机制,确保共享变量的互斥访问,防止数据不一致
* 2. synchronized关键字包括monitor enter和monitor exit两个JVM指令,能够保证在
* 任何时候任何线程执行到monitor enter成功之前都必须从主内存中获取数据,而不是从
* 缓存中,在monitor exit运行成功之后,共享变量被更新后的值必须存入主存
* 3. synchronized的指令严格遵守java happens-before规则,一个monitor exit指令
* 之前必定要有一个monitor enter
* @Author Cays
* @Date 2019/3/11 12:15
* @Version 1.0
**/
public class TicketWindowRunnable implements Runnable {
//synchronized叫号程序
private int index=1;
private final static int MAX=500;
public final static Object MUTEX=new Object();
@Override
public void run() {
//互斥机制,同一时刻只能有一个线程访问同步资源
//锁不正确,而是线程获取了与mutex关联的monitor锁
synchronized (MUTEX) {
while (index <= MAX) {
System.out.println(Thread.currentThread() + "的号码是:" + (index++));
}
}
}
public static void main(String []args){
final TicketWindowRunnable task=new TicketWindowRunnable();
Thread win1=new Thread(task,"一号窗口");
Thread win2=new Thread(task,"二号窗口");
Thread win3=new Thread(task,"三号窗口");
Thread win4=new Thread(task,"四号窗口");
win1.start();win2.start();
win3.start();win4.start();
}
}
三、运行结果
四、synchronized需要注意的问题
package safe;
import java.util.concurrent.TimeUnit;
/**
* @ClassName Mutex
* @Description TODO
* 1. monitor enter
* 每一个对象都与一个monitor相关联,一个monitor的lock锁只能被一个线程在同一时间获得,
* 在一个线程尝试获得与关联monitor的所有权时会发生如下几件事:
* (1)如果monitor的计数器为0,则意味着该monitor的lock还没有被获得,某个线程获得后立即对
* 该计数器加一,该线程成了该monitor的所有者
* (2)如果一个已拥有该monitor所有权的线程重入,则会导致monitor计数器累加
* (3)如果monitor已经被其他线程所拥有,则其他线程尝试获取该monitor的所有权时,
* 会被阻塞到monitor的计数器变为0,才能再次尝试获取该monitor的所有权
* 2. monitor exit
* 释放对monitor的所有权,将monitor计数器减一
* @Author Cays
* @Date 2019/3/11 12:39
* @Version 1.0
**/
public class Mutex {
// synchronized需要注意的问题
// 1. 与monitor关联的对象不能为空 private final Object mutex = null
// 2. synchronized作用域太大(串行代码效率低)
// 3. 不同的monitor企图锁同一个方法(自定义的thread实现Runnable接口)
// 4. 锁交叉导致死锁
private final static Object MUTEX=new Object();
public void accessResource(){
synchronized (MUTEX){
try {
TimeUnit.MILLISECONDS.sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
public static void main(String []args){
final Mutex mutex=new Mutex();
for (int i=0;i<5;i++){
new Thread(mutex::accessResource).start();
}
}
}