Java 关键字【synchronized】
Java 关键字【synchronized】
-
是什么
synchronized是Java的一个关键字,是 Java 语言内置的同步机制,由 JVM 实现,它提供了一种互斥机制,用于线程同步,确保在同一时刻只有一个线程能访问被synchronized修饰的方法(代码块);当然这在多线程中才有发挥的空间,可以防止多个线程同时访问和修改共享数据,保持数据的一致性。
-
怎么用
-
修饰代码块
使用
synchronized
关键字来修饰一个代码块,语法为synchronized (对象表达式) {代码块}
// 源码 java.lang.ClassLoader.class protected Class<?> loadClass(String name, boolean resolve) throws ClassNotFoundException { // 为了保证类加载过程的原子性和正确性,使用了synchronized synchronized (getClassLoadingLock(name)) { // First, check if the class has already been loaded Class<?> c = findLoadedClass(name); if (c == null) { long t0 = System.nanoTime(); try { if (parent != null) { c = parent.loadClass(name, false); } else { c = findBootstrapClassOrNull(name); } } catch (ClassNotFoundException e) { // ClassNotFoundException thrown if class not found // from the non-null parent class loader } if (c == null) { // If still not found, then invoke findClass in order // to find the class. long t1 = System.nanoTime(); c = findClass(name); // this is the defining class loader; record the stats PerfCounter.getParentDelegationTime().addTime(t1 - t0); PerfCounter.getFindClassTime().addElapsedTimeFrom(t1); PerfCounter.getFindClasses().increment(); } } if (resolve) { resolveClass(c); } return c; } }
-
修饰方法:
当 synchronized 修饰一个实例方法时,它会锁定当前对象的实例
// 源码 Thread类中的start()方法 /** 使用 synchronized 修饰 Thread 的 start 方法是为了保证线程状态转换的一致性、线程组操作的安全性以及避免并发执行 start0 方法,确保线程启动的过程是线程安全的,避免多个线程并发修改线程相关状态和调用 start0 方法导致的各种错误和异常。这种同步机制保证了 Thread 类在多线程环境下的正常工作和正确使用。 **/ public synchronized void start() { /** * This method is not invoked for the main method thread or "system" * group threads created/set up by the VM. Any new functionality added * to this method in the future may have to also be added to the VM. * * A zero status value corresponds to state "NEW". */ if (threadStatus != 0) throw new IllegalThreadStateException(); /* Notify the group that this thread is about to be started * so that it can be added to the group's list of threads * and the group's unstarted count can be decremented. */ group.add(this); boolean started = false; try { start0(); started = true; } finally { try { if (!started) { group.threadStartFailed(this); } } catch (Throwable ignore) { /* do nothing. If start0 threw a Throwable then it will be passed up the call stack */ } } }
-
-
为啥可以这样用
- 当一个线程访问被synchronized修饰的代码时,它首先检查锁是否可用。如果锁可用,线程会获取锁并进入代码块或者方法执行。如果锁不可用(已经被其他线程获取),当前线程会被阻塞,进入等待状态,直到锁被释放。
- 线程执行完被synchronized修饰的代码,它会释放锁,使得其他等待的线程有机会获取锁并执行。
-
这样用的好处与坏处
-
好处: 保证线程安全
-
坏处: 带来一定的性能开销,因为线程的阻塞和唤醒操作需要消耗系统资源,而且过多的锁竞争会导致线程频繁的等待,降低程序的并发性能。
-
建议: 只对真正需要同步的代码进行保护,尽量缩短synchronized代码块的范围。
-