• Java并发编程(四) —— synchronized


    一、概念

    利用锁机制实现线程同步,synchronized关键字的底层交由了JVM通过C++来实现

    Java中的锁有两大特性:

    • 互斥性
      • 同一时间,只允许一个线程持有某个对象锁。
    • 可见性
      • 锁释放前,线程对变量的修改,后面获得锁的线程可见。

    可见性

    JMM关于synchronized的两条规定:

    1. 线程解锁前,必须把共享变量的最新值刷新到主内存中

    2. 线程加锁时,将清空工作内存中共享变量的值,从而使用共享变量时需要从主内存中重新获取最新的值(注意:加锁与解锁需要是同一把锁)

    通过以上两点,可以看到synchronized能够实现可见性。

    二、用法

    synchronized修饰位置与锁的关系

    • 同步方法 —— 对象锁,当前实例对象
    • 静态同步方法 —— 类对象锁,当前对象的Class对象
    • 同步方法块 —— 对象锁,synchonized括号里配置的对象
    
    public class SynchronizedDemo {
    
        private static int m = 0;
    
        private Object obj = new Object();
    
        /**
         * 修饰非静态方法
         */
        public synchronized void m1() {
            sleep(2);
            m++;
        }
    
        /**
         * 修饰静态方法
         */
        public synchronized static void m2() {
            sleep(2);
            m++;
        }
    
        /**
         * 同步代码块,对对象加锁
         */
        public synchronized void m3() {
            synchronized (this) {
                sleep(2);
                m++;
            }
        }
    
        public synchronized void m4() {
            synchronized (obj) {
                sleep(2);
                m++;
            }
        }
    
        /**
         * 同步代码块,对类加锁
         */
        public synchronized void m5() {
            synchronized (SynchronizedDemo.class) {
                sleep(2);
                m++;
            }
        }
    
        public static void sleep(int second) {
    
            try {
                Thread.sleep(second * 1_000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    
    
    }
    
    
    

    三、面试问题

    同一个对象在A、B两个线程中分别访问该对象的两个同步方法writer和reader,是否会产生互斥?

    
    class LockDemo{
    	
    	int a = 0;
    	
    	public synchronized void writer(){
    		sleep(10);
    		a++;
    	}
    	
    	public synchronized void reader(){
    		int i = a;
    	}
    	
    	public static void main(String[] args) {
    	
            Test test = new Test();
            new Thread(() -> {
                test.writer();
            }).start();
            
            sleep(1);
            
            new Thread(() -> {
                test.reader();
            }).start();
    
        }
    
    }
    
    
    

    答案:会。因为synchronized修饰的是方法,锁是对象锁,默认当前的对象作为锁的对象。只有当A释放锁之后,B才会获得对象的锁。

    (1)如果是换成是不同对象呢?

    不会互斥,因为锁的是对象,而不是方法

    (2)如果writer、reader方法加上static修饰,两个线程中,类直接调用两个方法呢?

    会互斥,因为锁的是Class对象。

    (3)如果writer方法用static修饰,reader方法不用呢?

    不会互斥。因为一个是对象锁,一个是Class对象锁,锁的类型不同。

  • 相关阅读:
    Java Web 之servlet完整教程
    datediff(date1,date2) 函数的使用
    服务器搭建相关总结
    Oracle中INSTR函数与SQL Server中CHARINDEX函数
    36大数据和about云的文章总结
    oracle中LPAD和RPAD函数的使用方法(加个人总结)
    日常SQL总结
    about云Hadoop相关技术总结
    6.5 hadoop集群运行
    股票主动资金变化曲线分析交易意向和趋势
  • 原文地址:https://www.cnblogs.com/fonxian/p/10872814.html
Copyright © 2020-2023  润新知