Java高并发编程学习--7. 线程的synchronized关键字

一、synchronized关键字

    1. synchronized关键字提供一种锁的机制,确保共享变量的互斥访问,防止数据不一致
    1. synchronized关键字包括monitor enter和monitor exit两个JVM指令,能够保证在任何时候任何线程执行到monitor enter成功之前都必须从主内存中获取数据,而不是从缓存中,在monitor exit运行成功之后,共享变量被更新后的值必须存入主存
    1. 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();
        }
    }
}

猜你喜欢

转载自blog.csdn.net/qq_39400984/article/details/89784938