概念
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
静态方法默认类锁。
结论
关注七爪网,获取更多APP/小程序/网站源码资源!
留言与评论(共有 0 条评论) “” |