• Java并发操作之synchronized互斥锁总结


    💡💡synchronized关键字是Java语言为开发人员提供的同步工具,可以将它看成是一个“语法糖
    synchronized要解决的问题就是——多线程并发执行过程中数据同步的问题
    Java通过synchronized指定同步块,从而能在指定块中避免数据竞争问题,对方法进行声明实际上也有一个对应的同步块范围,而且会指定一个对应的锁对象。同一时刻只有一个线程能进入锁中,其他线程必须等待锁里的线程出来后才能够依次进入。
    synchronized不同的作用方式会导致不一样的作用范围,可通过修饰不同的对象实现锁范围,在代码上则是体现为代码块
    这里会扯到操作的原子性,不了解的朋友可以先去了解一下什么是原子性操作

    在这里插入图片描述

    总的来说,它们之间的区别就是:
    作用在对象方法上和作用在对象方法里面,它们锁住的对象是一样的,作用范围都是在对象上,对象充当了锁。(注意:类可以实例化多个对象,这个时候每个对象都是一个锁,即每个对象锁的作用范围都是相对于自己的对象来说的。)
    剩下的两个作用在类静态方法上和方法里面的,它们锁住的是类本身

    下面来几个简单案例

    作用在对象方法上

    最终想要实现的效果是两个都输出60000

    package com.java.code6;
    
    public class SynchronizedDemo2 {
    
    	int count = 0;
    	int count2 = 0;
    
    	public  void add() {
    		count++;
    	}
    	public synchronized void add2() {
    		count2++;
    	}
    
    	public static void main(String[] args) throws InterruptedException {
    		SynchronizedDemo2 demo = new SynchronizedDemo2();
    
    		for (int i = 0; i < 10; i++){
                new Thread(() -> {
                    for (int j = 0; j < 6000; j++){
                        demo.add();
                    }
    
                }).start();
            }
    
    		for (int i = 0; i < 10; i++){
                new Thread(() -> {
                    for (int j = 0; j < 6000; j++){
                        demo.add2();
                    }
                }).start();
            }
    
    
    		Thread.sleep(3000);
    		System.out.println("count = " + demo.count);
    		System.out.println("count2 = " + demo.count2);
    	}
    }
    

    在这里插入图片描述

    可以看到只有count2完成了我们的预期:60000
    这里可以不用关心count的最终结果,因为它肯定小于60000,因为在count对应的方法里这里的++操作是非原子的操作

    问:如果是两个不同的方法呢?如果是两个不同的方法,那么效果会是怎么样的呢?

    以下定义了两个方法,看看效果

    package com.java.code6;
    
    public class SynchronizedDemo8 {
    
    	public synchronized void method(String name) {
    		System.out.println(name + " gets the lock.");
    		sleep(3000);
    		System.out.println(name + " releases the lock after 3s.");
    	}
    
    	public synchronized void method2(String name) {
    		System.out.println(name + " gets the lock.");
    		sleep(3000);
    		System.out.println(name + " releases the lock after 3s.");
    	}
    
    	public static void sleep(int s) {
    		try {
    			Thread.sleep(s);
    		} catch (InterruptedException e) {
    		}
    	}
    
    	public static void main(String[] args) throws InterruptedException {
    		SynchronizedDemo8 demo = new SynchronizedDemo8();
    
    		new Thread(() -> {
    			demo.method("thread1");
    		}).start();
    
    		new Thread(() -> {
    			demo.method2("thread2");
    		}).start();
    
    	}
    }
    

    在这里插入图片描述

    同样这两个线程还是会产生互斥效果,声明的两个不同对象方法都是以当前对象作为锁,那么肯定就还是会产生互斥效果。

    作用在类静态方法上

    作用在类静态方法上是以类作为锁🍐🍐🍐

    package com.java.code6;
    
    public class SynchronizedDemo4 {
    
    	static int count = 0;
    
    	public synchronized static void add() {
    		count++;
    	}
    
    	public static void main(String[] args) throws InterruptedException {
    
    		for (int i = 0; i < 10; i++){
    			new Thread(() -> {
    				for (int j = 0; j < 10000; j++){
    					add();
    				}
    			}).start();
    		}
    
    
    		Thread.sleep(3000);
    		System.out.println("count = " + count);
    	}
    }
    

    在这里插入图片描述

    可以看到,达到我们的目标:100000

    作用在类静态方法和对象方法上的区别

    package com.java.code6;
    
    public class SynchronizedDemo5 {
    
    	public synchronized void method(String name) {
    		System.out.println(name + " gets the lock.");
    		sleep(3000);
    		System.out.println(name + " releases the lock after 3s.");
    	}
    
    	public static synchronized void method2(String name) {
    		System.out.println(name + " gets the lock.");
    		sleep(3000);
    		System.out.println(name + " releases the lock after 3s.");
    	}
    
    	public static void sleep(int s) {
    		try {
    			Thread.sleep(s);
    		} catch (InterruptedException e) {
    		}
    	}
    
    	public static void main(String[] args) throws InterruptedException {
    		SynchronizedDemo5 demo = new SynchronizedDemo5();
    
    		new Thread(() -> {
    			demo.method("thread1");
    		}).start();
    
    		new Thread(() -> {
    			method2("thread2");
    		}).start();
    
    	}
    }
    

    在这里插入图片描述

    可以看到2个线程没有产生互斥效果,因为method是以当前对象作为锁,而method2是以SynchronizedDemo5.class对象作为锁,锁不同自然就不存在互斥效果。

    最后,补充作用在对象方法里面和类静态方法里面,这两个方法和对应作用在对象方法上和作用在类静态方法上是共用一个锁的。也就是这两个方法和前面两个效果一样,大家可以去试试玩一玩,验证一下。

  • 相关阅读:
    前端常见专有名词
    数据分析:小红书品牌“共情力”缔造指南
    Spark集成hudi创建表报错
    24计算机考研深大经验分享(计算机专业考研综合安排)
    以汇川中型PLC(AM系列)为例,CODESYS平台变量与字节数组互转的多种方法
    给Tomcat添加第三方jar包、如何在IDEA中启动部署Web模板
    【知识积累】利用BeanDefinitionRegistryPostProcessor修改Mybatis的mapper代理对象
    剑指 Offer 03. 数组中重复的数字
    市值缩水90%以上,泛生子何以败退美股?
    C#运算符和流程控制语句
  • 原文地址:https://blog.csdn.net/Xmumu_/article/details/127035941