您的位置 首页 java

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

七爪源码: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 Sync Thread ();
        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 (Interrupted Exception  e) {
                e.printStackTrace();
            }
        }
    }
F_thread1_Sync: 23:20:55
F_thread2_Sync: 23:20:55
F_thread4_Sync: 23:20:55
F_thread3_Sync: 23:20:55
F_thread1_Sync_Start: 23:20:55
F_thread2_Sync_Start: 23:20:55
F_thread4_Sync_Start: 23:20:55
F_thread3_Sync_Start: 23:20:55
F_thread4_Sync_End: 23:20:57
F_thread1_Sync_End: 23:20:57
F_thread3_Sync_End: 23:20:57
F_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:11
F_thread2_Sync: 23:23:11
F_thread3_Sync: 23:23:11
F_thread4_Sync: 23:23:11
F_thread1_Sync_Start: 23:23:11
F_thread1_Sync_End: 23:23:13
F_thread4_Sync_Start: 23:23:13
F_thread4_Sync_End: 23:23:15
F_thread3_Sync_Start: 23:23:15
F_thread3_Sync_End: 23:23:17
F_thread2_Sync_Start: 23:23:17
F_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:56
F_thread2_Sync: 23:23:56
F_thread3_Sync: 23:23:56
F_thread1_Sync_Start: 23:23:56
F_thread4_Sync: 23:23:56
F_thread2_Sync_Start: 23:23:56
F_thread3_Sync_Start: 23:23:56
F_thread1_Sync_End: 23:23:58
F_thread2_Sync_End: 23:23:58
F_thread3_Sync_End: 23:23:58
F_thread4_Sync_Start: 23:23:58
F_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:38
F_thread3_Sync: 23:26:38
F_thread2_Sync_Start: 23:26:38
F_thread3_Sync_Start: 23:26:38
F_thread1_Sync: 23:26:38
F_thread1_Sync_Start: 23:26:38
F_thread3_Sync_End: 23:26:40
F_thread2_Sync_End: 23:26:40
F_thread1_Sync_End: 23:26:40
F_thread4_Sync: 23:26:40
F_thread4_Sync_Start: 23:26:40
F_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:47
F_thread1_Sync_Start: 23:28:47
F_thread1_Sync_End: 23:28:49
F_thread4_Sync: 23:28:49
F_thread4_Sync_Start: 23:28:49
F_thread4_Sync_End: 23:28:51
F_thread3_Sync: 23:28:51
F_thread3_Sync_Start: 23:28:51
F_thread3_Sync_End: 23:28:53
F_thread2_Sync: 23:28:53
F_thread2_Sync_Start: 23:28:53
F_thread2_Sync_End: 23:28:55  

静态方法默认类锁。

结论

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

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

文章来源:智云一二三科技

文章标题:七爪源码:Java中的同步(this)VS同步(class)

文章地址:https://www.zhihuclub.com/187490.shtml

关于作者: 智云科技

热门文章

网站地图