内置锁:每个java对象都可以用做一个实现同步的锁,这些锁称为内置锁。线程进入同步代码块或方法的时候会自动获得该锁,在退出同步代码块或方法时会释放该锁。获得内置锁的唯一途径就是进入这个锁的保护的同步代码块或方法。
互斥锁:内置锁是一个互斥锁,这就是意味着最多只有一个线程能够获得该锁,当线程A尝试去获得线程B持有的内置锁时,线程A必须等待或者阻塞,直到线程B释放这个锁,如果B线程不释放这个锁,那么A线程将永远等待下去。
synchronized既是内置锁也是互斥锁
synchronized三种修饰
第一、修饰普通方法
代码示例:
public class TestSynchronized { public synchronized void out() throws InterruptedException { System.out.println("test开始.."); try { Thread.sleep(5000L); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("test结束.."); } public static void main(String[] args) { TestSynchronized testSync = new TestSynchronized(); TestSynchronized testSync2 = new TestSynchronized(); new Thread(() -> { try { testSync.out(); } catch (InterruptedException e) { e.printStackTrace(); } }).start(); new Thread(() -> { try { testSync2.out(); } catch (InterruptedException e) { e.printStackTrace(); } }).start(); } }控制台输出:
test开始.. test开始.. test结束.. test结束..很明显,synchronized修饰普通方法的时候,锁住的是对象的实例,代码示例中,testSync 和testSync2分别都是TestSynchronized对象的实例,他们两个都可以同时进入synchronized修饰的普通方法,所以得出,synchronized修饰普通方法的时候,锁住的是对象的实例。
第二、修饰静态方法
代码示例:
public class TestSynchronized { public static synchronized void staticOut() throws InterruptedException { long startTime = System.currentTimeMillis(); System.out.println("test开始.."); try { Thread.sleep(5000L); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("test结束.."); long endTime = System.currentTimeMillis(); System.out.println("线程"+Thread.currentThread().getName() + "程序运行时间:" + (endTime - startTime) + "ms"); } public static void main(String[] args) { TestSynchronized testSync = new TestSynchronized(); TestSynchronized testSync2 = new TestSynchronized(); new Thread(() -> { try { testSync.staticOut(); } catch (InterruptedException e) { e.printStackTrace(); } }).start(); new Thread(() -> { try { testSync2.staticOut(); } catch (InterruptedException e) { e.printStackTrace(); } }).start(); } }控制台输出:
test开始.. test结束.. 线程Thread-0程序运行时间:5000ms test开始.. test结束.. 线程Thread-1程序运行时间:5000ms可以看出,synchronized修饰静态方法的时候,起到了锁的作用,线程分别获得锁后才进入静态方法中,但是尽量不要使用synchronized修饰静态方法,因为它锁住的是整个类,也就是说,在整个类中的其他synchronized修饰的方法都会被锁住。
示例代码如下:
public class TestSynchronized { public static synchronized void staticOut() throws InterruptedException { long startTime = System.currentTimeMillis(); System.out.println("test开始.."); try { Thread.sleep(5000L); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("test结束.."); long endTime = System.currentTimeMillis(); System.out.println("线程"+Thread.currentThread().getName() + "程序运行时间:" + (endTime - startTime) + "ms"); } public static synchronized void staticOut2() throws InterruptedException { long startTime = System.currentTimeMillis(); System.out.println("test2开始.."); try { Thread.sleep(5000L); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("test2结束.."); long endTime = System.currentTimeMillis(); System.out.println("线程"+Thread.currentThread().getName() + "程序运行时间:" + (endTime - startTime) + "ms"); } public static void main(String[] args) { TestSynchronized testSync = new TestSynchronized(); TestSynchronized testSync2 = new TestSynchronized(); new Thread(() -> { try { testSync.staticOut(); } catch (InterruptedException e) { e.printStackTrace(); } }).start(); new Thread(() -> { try { testSync2.staticOut2(); } catch (InterruptedException e) { e.printStackTrace(); } }).start(); } }控制台输出:
test开始.. test结束.. 线程Thread-0程序运行时间:5000ms test2开始.. test2结束.. 线程Thread-1程序运行时间:5001ms可以看出,线程Thread-0进入synchronized修饰的静态方法staticOut()的时候,这个类就被锁住了,线程Thread-1无法获得锁,只能等待锁的释放后才能进入方法staticOut2()。所以使用synchronized修饰静态方法需要慎重。
第三、修饰代码块
示例代码:
public class TestSynchronized { private Object lock = new Object(); public void lockOut(){ synchronized(lock){ long startTime = System.currentTimeMillis(); System.out.println("test开始.."); try { Thread.sleep(5000L); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("test结束.."); long endTime = System.currentTimeMillis(); System.out.println("线程"+Thread.currentThread().getName() + "程序运行时间:" + (endTime - startTime) + "ms"); } } public static void main(String[] args) { TestSynchronized testSync = new TestSynchronized(); TestSynchronized testSync2 = new TestSynchronized(); new Thread(() -> { testSync.lockOut(); }).start(); new Thread(() -> { testSync2.lockOut(); }).start(); } }控制台输出:
test开始.. test开始.. test结束.. test结束.. 线程Thread-0程序运行时间:5000ms 线程Thread-1程序运行时间:5000mssynchronized修饰代码块时,锁住的是一个对象 synchronized (lock) 即synchronized后面括号里的内容,因为两个对象创建了两个不同对象实例lock,所以两个对象的线程都可以同时进入synchronized修饰代码块。如果想锁住synchronized修饰的代码块,只需要确定synchronized后面括号里锁住同一
对象即可,常用的方法如下:
1、synchronized锁这个类对应的Class对象。
实例代码:
public class TestSynchronized { // private Object lock = new Object(); public void lockOut(){ synchronized(TestSynchronized.class){ long startTime = System.currentTimeMillis(); System.out.println("test开始.."); try { Thread.sleep(5000L); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("test结束.."); long endTime = System.currentTimeMillis(); System.out.println("线程"+Thread.currentThread().getName() + "程序运行时间:" + (endTime - startTime) + "ms"); } } public static void main(String[] args) { TestSynchronized testSync = new TestSynchronized(); TestSynchronized testSync2 = new TestSynchronized(); new Thread(() -> { testSync.lockOut(); }).start(); new Thread(() -> { testSync2.lockOut(); }).start(); } }控制台输出:
test开始.. test结束.. 线程Thread-0程序运行时间:5001ms test开始.. test结束.. 线程Thread-1程序运行时间:5002ms让synchronized锁这个类对应的Class对象这种方法实现了全局锁的效果,和synchronized修饰静态方法一样(static synchronized方法也是相当于全局锁),整个类就被锁住了,所以此方法一样需要慎重使用。
2、创建一个单例对象,锁住的是该单例对象,单例对象只有一个实例。
public class TestSynchronized { private volatile static Object lock = new Object(); public void lockOut(){ synchronized(lock){ System.out.println("指针地址:" + lock.toString()); long startTime = System.currentTimeMillis(); System.out.println("test开始.."); try { Thread.sleep(5000L); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("test结束.."); long endTime = System.currentTimeMillis(); System.out.println("线程"+Thread.currentThread().getName() + "程序运行时间:" + (endTime - startTime) + "ms"); } } public static void main(String[] args) { TestSynchronized testSync = new TestSynchronized(); TestSynchronized testSync2 = new TestSynchronized(); new Thread(() -> { testSync.lockOut(); }).start(); new Thread(() -> { testSync2.lockOut(); }).start(); } }控制台输出:
指针地址:java.lang.Object@ce407e7 test开始.. test结束.. 线程Thread-0程序运行时间:1000ms 指针地址:java.lang.Object@ce407e7 test开始.. test结束.. 线程Thread-1程序运行时间:1001ms保证了单例对象lock 的实例唯一性,synchronized锁住同一个固定对象,从控制台上可以看出,访问代码块的对象指针地址是一样的。
3、访问该代码块的对象唯一
示例代码:
public class TestSynchronized { // private volatile static Object lock = new Object(); public void lockOut(){ synchronized(this){ System.out.println("指针地址:" + this.toString()); long startTime = System.currentTimeMillis(); System.out.println("test开始.."); try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("test结束.."); long endTime = System.currentTimeMillis(); System.out.println("线程"+Thread.currentThread().getName() + "程序运行时间:" + (endTime - startTime) + "ms"); } } public static void main(String[] args) { TestSynchronized testSync = new TestSynchronized(); new Thread(() -> { testSync.lockOut(); }).start(); new Thread(() -> { testSync.lockOut(); }).start(); } }控制台输出:
指针地址:com.test.test.TestSynchronized@1dca18a4 test开始.. test结束.. 线程Thread-0程序运行时间:1000ms 指针地址:com.test.test.TestSynchronized@1dca18a4 test开始.. test结束.. 线程Thread-1程序运行时间:1000mssynchronized后面括号的this指的是访问该代码块的对象,从控制台上可以看出,访问代码块的对象指针地址是一样的,从而可以得出他们是固定同一对象。
相关推荐
在多线程编程中,确保线程安全是至关重要的。Java提供了多种机制来处理并发问题,其中synchronized...通过深入理解synchronized关键字,开发者可以更好地处理Java中的并发问题,构建出更加健壮和高效的多线程应用程序。
但是,很多开发者对 synchronized 关键字的理解并不够深入,本文将通过实例解析 Java 中的 synchronized 关键字与线程平安问题,帮助开发者更好地理解和使用 synchronized 关键字。 首先,需要清晰的是 ...
本文将深入探讨`synchronized`的两种主要用法:synchronized方法和synchronized块。 1. **synchronized 方法** synchronized方法是通过在方法声明前添加`synchronized`关键字来定义的。例如: ```java public ...
《深入理解Java中的synchronized关键字》 在Java编程语言中,`synchronized`关键字是用于实现线程同步的重要工具,它的本质在于确保多线程环境下的数据一致性与安全性。通过`synchronized`,我们可以控制对共享资源...
一、synchronized关键字的作用与原理 `synchronized`关键字主要有两个作用:同步方法和同步块。它通过锁机制来实现线程同步,防止多个线程同时执行同一段代码,可能导致的数据不一致问题。 1. 同步方法:当在方法...
本文将深入探讨`synchronized`关键字的使用及其在实际编程中的应用。 `synchronized`可以应用于以下几种形式: 1. **synchronized 代码块**:同步代码块的形式为 `synchronized (object) { ... }`,其中`object`是...
本篇将详细解析`synchronized`的关键特性和使用方法,帮助开发者深入理解如何在并发编程中有效地利用这一特性。 1. **synchronized的两种使用方式** - **方法同步**:通过在方法声明前加上`synchronized`关键字,...
【深入讲解Java线程与synchronized关键字】 Java中的多线程同步是通过对象锁机制来实现的,synchronized关键字正是这一机制的关键。它确保了在任何时刻,只有一个线程能够访问特定的共享资源,从而避免数据不一致的...
【深入理解synchronized】 在Java多线程编程中,`synchronized`关键字是实现线程安全的关键工具之一,它提供了一种同步机制,确保共享资源在同一时间只能被一个线程访问。本文将从应用层、字节码层面和Java虚拟机...
【标题】:深入解析Synchronized关键字与JVM源码 【描述】:本文将全面剖析Java中的Synchronized关键字,从基础概念到高级机制,包括其在JVM中的实现原理和锁升级过程。我们将探讨它的使用方式,特点以及如何在并发...
在这个问题中,我们将深入理解`synchronized`的关键字用法,包括同步方法和同步块。 1. **同步方法**: 当`synchronized`关键字修饰一个方法时,这个方法称为同步方法。这意味着当一个线程进入这个方法时,它会...
理解并正确使用synchronized关键字是Java多线程编程的关键,它可以帮助开发者防止数据不一致性和线程竞态条件,确保多线程环境下的数据安全。然而,过度使用synchronized可能导致性能下降,因此需要根据具体应用场景...
本文将详细介绍 Java 中 synchronized 的正确使用方法,通过示例代码和实践案例,帮助读者深入理解 synchronized 的使用方法和原理。 一、并行和锁 并行是一种提高程序效率的方式,它允许多个线程同时执行,提高...
4. **多线程**:了解线程的创建(Thread类、Runnable接口)、同步机制(synchronized关键字、wait()、notify()、notifyAll()方法)、线程池(ExecutorService、ThreadPoolExecutor)以及并发工具类(Semaphore、...
在Java编程语言中,`synchronized`关键字是用于处理多线程环境下的线程安全问题的关键工具。...在处理线程安全问题时,不仅要理解`synchronized`的工作原理,还要深入理解Java内存模型和并发编程的最佳实践。
Java并发编程中的synchronized关键字是实现线程安全的重要工具,它提供了一种互斥访问机制,确保了共享数据在同一时刻只能被一个线程访问。synchronized关键字有三种主要的应用方式: 1. 修饰实例方法:当...
- 同步块/同步方法(使用`synchronized`关键字) - 使用`Lock`接口及其实现(如`ReentrantLock`) - 线程局部变量(`ThreadLocal`) 8. **线程状态转换** - 新建(New)、就绪(Runnable)、运行(Running)、...
本测试案例深入探讨了`synchronized`的使用方法,包括同步单个对象、同步多个对象以及成功与失败的场景对比。 一、`synchronized`关键字的基本概念 `synchronized`关键字可以修饰方法或用作代码块,其主要作用是...
synchronized方法是通过在方法声明前加上synchronized关键字来实现的,而synchronized块则是在代码块前加上关键字,指定一个监视器对象,只有获取到该对象锁的线程才能执行该代码块。 在Java 6之后,synchronized...