synchronized

Posted 无赖H4

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了synchronized相关的知识,希望对你有一定的参考价值。


synchronized 是一种保护线程安全的机制。

synchronized语法

  1. 修饰任意的方法——方法修饰关键字
  • 普通方法
	synchronized void m2() {}
  • 静态方法
	static synchronized void m3() {}
  1. 同步代码块——可能出现在语句的位置(方法中,构造代码块中,静态代码块)
	Object  o = new Object();
	synchronized(o/*任意类型的引用*/){
	//语句
	}

预备知识

Class 是描述 类(Class)的类。
描述一个类的类,有且仅有一个。

例如:
Person p = new Person();
Class c1 = p.getClass();
Class c2 = Person.class;
c1 == c2 是true,引用指的是同一个对象;

Java中的对象中,有哪些数据:
在这里插入图片描述
任意的Java中的对象,都内含一把锁,这把锁被称为 同步锁/监视器锁
另外还包括Class对象

synchronized关键字的作用

以同步代码块为例:
在这里插入图片描述
这个引用不可以是null,否则会有NPE

注意:
synchronized修饰普通方法,视为对this加锁
synchronized修饰静态方法,视为对XX.class加锁

两个线程互斥

线程之间如何因为 锁 发生争抢——两个线程互斥
例如:

import java.util.Scanner;
import java.util.concurrent.TimeUnit;

class MyThread extends Thread {
    @Override
    public void run() {
        try {
            TimeUnit.MILLISECONDS.sleep(10);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("子线程:语句1");
        synchronized (SyncDemo2.o) {
            System.out.println("子线程: 语句2");
        }
        System.out.println("子线程: 语句3");
    }
}
public class SyncDemo2 {
    public static Object o;
    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        MyThread t = new MyThread();
        t.start();
        synchronized (o) {
            System.out.println("主线程:等待输入");
            scanner.nextLine();
            System.out.println("主线程: 马上释放锁");
        }
    }
}

只有前一个释放锁后,另外一个线程才能加锁开始执行(互斥)

例子:

void m1() {}
    synchronized void m2() {}
    static synchronized void m3() {}
    void m4() {
        synchronized (this) {}
    }
    static void m5() {
        synchronized (SyncDemo4.class) {}
    }
    void m6() {
        synchronized (SyncDemo4.class) {}
    }
    void m7() {
        synchronized (getClass()) {}
    }

在这里插入图片描述
上面的例子也体现了:
synchronized修饰普通方法,视为对this加锁
synchronized修饰静态方法,视为对XX.class加锁

两个线程要出现互斥:

1、两个线程都有加锁操作
2、两个线程加的是同一把锁

synchronized 加锁的过程

  1. 根据引用找到对象,加锁
  2. 加锁成功,直接向下执行
  3. 加锁失败
    1、把自己的对象放到这把锁的阻塞队列中
    2、把状态变更为一种阻塞状态(BLOCKED)——专为同步锁加锁失败设计
    3、主动放弃CPU

synchronized 释放锁的过程

1、释放锁
2、把这把锁的阻塞队列中等待的线程们,状态改为就绪(一个或多个,释放那个)

synchronized容易被忽视的地方

当加锁后,上下两个语句间的间隔不确定(不知道何时释放锁)

synchronized的作用

  1. 保护原子性 (需要保证互斥)
  2. 内存可见性一直
    1、一旦加锁成功,必须从主存储中,将最新的数据同步到工作存储中——保证线程看到的最新数据
    2、释放锁的时候,必须做一次把工作存储的数据刷会主存储的操作(保证主存储中是最新的数据)
  3. 代码重排序
    1、会一定程度上保持代码重排序
    在这里插入图片描述

以上是关于synchronized的主要内容,如果未能解决你的问题,请参考以下文章

同步代码 [重复]

#yyds干货盘点# Java | 关于synchronized相关理解

Java初识方法

并发技术12线程锁技术的使用

Java并发编程实战—–synchronized

Java多线程与并发库高级应用-工具类介绍