Java 关键字【synchronized】
-
是什么
synchronized是Java的一个关键字,是 Java 语言内置的同步机制,由 JVM 实现,它提供了一种互斥机制,用于线程同步,确保在同一时刻只有一个线程能访问被
synchronized
修饰的方法(代码块);当然这在多线程中才有发挥的空间,可以防止多个线程同时访问和修改共享数据,保持数据的一致性。 -
怎么用
-
修饰代码块
使用
synchronized
关键字来修饰一个代码块,语法为synchronized (对象表达式) {代码块}
// 源码 java.lang.ClassLoader.class protected Class<?> loadClass(String name, boolean resolve)throws ClassNotFoundException{// 为了保证类加载过程的原子性和正确性,使用了synchronizedsynchronized (getClassLoadingLock(name)) {// First, check if the class has already been loadedClass<?> 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 statsPerfCounter.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 thenit will be passed up the call stack */}}}
-
-
为啥可以这样用
- 当一个线程访问被
synchronized
修饰的代码时,它首先检查锁是否可用。如果锁可用,线程会获取锁并进入代码块或者方法执行。如果锁不可用(已经被其他线程获取),当前线程会被阻塞,进入等待状态,直到锁被释放。 - 线程执行完被
synchronized
修饰的代码,它会释放锁,使得其他等待的线程有机会获取锁并执行。
- 当一个线程访问被
-
这样用的好处与坏处
-
好处: 保证线程安全
-
坏处: 带来一定的性能开销,因为线程的阻塞和唤醒操作需要消耗系统资源,而且过多的锁竞争会导致线程频繁的等待,降低程序的并发性能。
-
建议: 只对真正需要同步的代码进行保护,尽量缩短synchronized代码块的范围。
-