七爪源码:Java中的同步(this)VS同步(class)

概念

Synchronized是Java中的一个关键字,它使用锁机制来实现同步。

锁定机构具有以下两个特点。

互斥:即只允许一个线程同时持有一个对象锁,该特性用于实现多线程中的协调机制,使得只有一个线程可以对代码块进行同步(复合操作) ) 同时。使用权。互斥也经常被称为操作的原子性。

可见性:必须保证在释放锁之前,对共享变量所做的修改对于后续获取锁的另一个线程是可见的(即在获取锁时应该获取最新的共享变量的值),否则另一个thread 不一致的原因可能是继续对本地缓存的副本进行操作。


对象锁和类锁

对象锁定

在Java中,每个对象都会有一个监控对象,也就是Java对象的锁,通常称为“内置锁”或“对象锁”。一个类中可以有多个对象,所以每个对象都有自己的对象锁,互不干扰。

类锁

在Java中,每个类也有一个锁,可以称为类锁。类锁是通过对象锁实现的,即类的类对象锁。每个类只有一个 Class 对象,因此每个类只有一个类锁。


同步使用分类

同步的使用可以分为两个维度。

1 按修饰对象分类

synchronized 可以装饰方法和代码块。

Decorated code block- synchronized(this|object) {}- synchronized(class.class) {}Modification method- Decorate a non-static method- Decorate static methods

2 按获取锁分类

Acquire object lock- synchronized(this|object) {}- Decorate a non-static methodAcquire class lock- Synchronized(class.class) {}- Decorate static methods, non-static methods


synchronized的使用详解

这里根据获取锁的分类来分析synchronized的用法。

文章中的所有示例都使用这四个线程。

public class medium01Test{    public static void main(String[] args) {        SyncThread syncThread = new SyncThread();        Thread F_thread1 = new Thread(new SyncThread(), "F_thread1");        Thread F_thread2 = new Thread(new SyncThread(), "F_thread2");        Thread F_thread3 = new Thread(syncThread, "F_thread3");        Thread F_thread4 = new Thread(syncThread, "F_thread4");        F_thread1.start();        F_thread2.start();        F_thread3.start();        F_thread4.start();    }}

1 使用对象锁

该对象是新创建的,与其他对象无关。

class SyncThread implements Runnable {    @Override    public void run() {        System.out.println(Thread.currentThread().getName() + "_Sync: " + new SimpleDateFormat("HH:mm:ss").format(new Date()));        synchronized (new SyncThread()) {            try {                System.out.println(Thread.currentThread().getName() + "_Sync_Start: " + new SimpleDateFormat("HH:mm:ss").format(new Date()));                Thread.sleep(2000);                System.out.println(Thread.currentThread().getName() + "_Sync_End: " + new SimpleDateFormat("HH:mm:ss").format(new Date()));            } catch (InterruptedException e) {                e.printStackTrace();            }        }    }F_thread1_Sync: 23:20:55F_thread2_Sync: 23:20:55F_thread4_Sync: 23:20:55F_thread3_Sync: 23:20:55F_thread1_Sync_Start: 23:20:55F_thread2_Sync_Start: 23:20:55F_thread4_Sync_Start: 23:20:55F_thread3_Sync_Start: 23:20:55F_thread4_Sync_End: 23:20:57F_thread1_Sync_End: 23:20:57F_thread3_Sync_End: 23:20:57F_thread2_Sync_End: 23:20:57

四个线程同时开始和结束,因为作为锁的对象和线程属于不同的实例。


2 使用类锁,不管是哪个类,都会被拦截

class SyncThread implements Runnable {    @Override    public void run() {        System.out.println(Thread.currentThread().getName() + "_Sync: " + new SimpleDateFormat("HH:mm:ss").format(new Date()));        synchronized (SyncThread.class) {            try {                System.out.println(Thread.currentThread().getName() + "_Sync_Start: " + new SimpleDateFormat("HH:mm:ss").format(new Date()));                Thread.sleep(2000);                System.out.println(Thread.currentThread().getName() + "_Sync_End: " + new SimpleDateFormat("HH:mm:ss").format(new Date()));            } catch (InterruptedException e) {                e.printStackTrace();            }        }    }}F_thread1_Sync: 23:23:11F_thread2_Sync: 23:23:11F_thread3_Sync: 23:23:11F_thread4_Sync: 23:23:11F_thread1_Sync_Start: 23:23:11F_thread1_Sync_End: 23:23:13F_thread4_Sync_Start: 23:23:13F_thread4_Sync_End: 23:23:15F_thread3_Sync_Start: 23:23:15F_thread3_Sync_End: 23:23:17F_thread2_Sync_Start: 23:23:17F_thread2_Sync_End: 23:23:19

可以发现,使用类锁一次只能通过一个。


3 使用这个对象锁

class SyncThread implements Runnable {    @Override    public void run() {        System.out.println(Thread.currentThread().getName() + "_Sync: " + new SimpleDateFormat("HH:mm:ss").format(new Date()));        synchronized (this) {            try {                System.out.println(Thread.currentThread().getName() + "_Sync_Start: " + new SimpleDateFormat("HH:mm:ss").format(new Date()));                Thread.sleep(2000);                System.out.println(Thread.currentThread().getName() + "_Sync_End: " + new SimpleDateFormat("HH:mm:ss").format(new Date()));            } catch (InterruptedException e) {                e.printStackTrace();            }        }    }}F_thread1_Sync: 23:23:56F_thread2_Sync: 23:23:56F_thread3_Sync: 23:23:56F_thread1_Sync_Start: 23:23:56F_thread4_Sync: 23:23:56F_thread2_Sync_Start: 23:23:56F_thread3_Sync_Start: 23:23:56F_thread1_Sync_End: 23:23:58F_thread2_Sync_End: 23:23:58F_thread3_Sync_End: 23:23:58F_thread4_Sync_Start: 23:23:58F_thread4_Sync_End: 23:24:00

线程 1 和 2 同时结束,线程 3 和 4 一个接一个。 原因是 3 和 4 属于同一个实例。


4 使用同步修改方法

作用域是整个方法,所以方法中的所有代码都是同步的。

class SyncThread implements Runnable {    @Override    public void run() {        sync();    }    public synchronized void sync() {        System.out.println(Thread.currentThread().getName() + "_Sync: " + new SimpleDateFormat("HH:mm:ss").format(new Date()));        try {            System.out.println(Thread.currentThread().getName() + "_Sync_Start: " + new SimpleDateFormat("HH:mm:ss").format(new Date()));            Thread.sleep(2000);            System.out.println(Thread.currentThread().getName() + "_Sync_End: " + new SimpleDateFormat("HH:mm:ss").format(new Date()));        } catch (InterruptedException e) {            e.printStackTrace();        }    }}F_thread2_Sync: 23:26:38F_thread3_Sync: 23:26:38F_thread2_Sync_Start: 23:26:38F_thread3_Sync_Start: 23:26:38F_thread1_Sync: 23:26:38F_thread1_Sync_Start: 23:26:38F_thread3_Sync_End: 23:26:40F_thread2_Sync_End: 23:26:40F_thread1_Sync_End: 23:26:40F_thread4_Sync: 23:26:40F_thread4_Sync_Start: 23:26:40F_thread4_Sync_End: 23:26:42

对于非静态方法,会拦截同一个实例的线程访问,可以同时访问不同的实例。 也就是此时默认的对象锁(this)。

class SyncThread implements Runnable {    @Override    public void run() {        sync();    }    public synchronized static void sync() {        System.out.println(Thread.currentThread().getName() + "_Sync: " + new SimpleDateFormat("HH:mm:ss").format(new Date()));        try {            System.out.println(Thread.currentThread().getName() + "_Sync_Start: " + new SimpleDateFormat("HH:mm:ss").format(new Date()));            Thread.sleep(2000);            System.out.println(Thread.currentThread().getName() + "_Sync_End: " + new SimpleDateFormat("HH:mm:ss").format(new Date()));        } catch (InterruptedException e) {            e.printStackTrace();        }    }}F_thread1_Sync: 23:28:47F_thread1_Sync_Start: 23:28:47F_thread1_Sync_End: 23:28:49F_thread4_Sync: 23:28:49F_thread4_Sync_Start: 23:28:49F_thread4_Sync_End: 23:28:51F_thread3_Sync: 23:28:51F_thread3_Sync_Start: 23:28:51F_thread3_Sync_End: 23:28:53F_thread2_Sync: 23:28:53F_thread2_Sync_Start: 23:28:53F_thread2_Sync_End: 23:28:55

静态方法默认类锁。


结论

  1. 对于静态方法,由于此时还没有生成对象,所以只能使用类锁。
  2. 只要使用类锁,所有线程都会被拦截,只能访问一个线程。
  3. 对于对象锁(this),如果是同一个实例,会顺序访问,如果是不同的实例,可以同时访问。
  4. 如果对象锁与被访问的对象无关,则两者会同时被访问。


关注七爪网,获取更多APP/小程序/网站源码资源!

源码   Java   this
发表评论
留言与评论(共有 0 条评论) “”
   
验证码:

相关文章

推荐文章