`
ninghq
  • 浏览: 11890 次
  • 性别: Icon_minigender_1
  • 来自: 深圳
社区版块
存档分类
最新评论

深入理解synchronized关键字的用法

    博客分类:
  • java
阅读更多

 

 内置锁:每个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程序运行时间:5000ms
 synchronized修饰代码块时,锁住的是一个对象 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程序运行时间:1000ms
 synchronized后面括号的this指的是访问该代码块的对象,从控制台上可以看出,访问代码块的对象指针地址是一样的,从而可以得出他们是固定同一对象。
分享到:
评论

相关推荐

    实例解析Java中的synchronized关键字与线程平安问题_.docx

    但是,很多开发者对 synchronized 关键字的理解并不够深入,本文将通过实例解析 Java 中的 synchronized 关键字与线程平安问题,帮助开发者更好地理解和使用 synchronized 关键字。 首先,需要清晰的是 ...

    synchronized关键字的实质及用法

    《深入理解Java中的synchronized关键字》 在Java编程语言中,`synchronized`关键字是用于实现线程同步的重要工具,它的本质在于确保多线程环境下的数据一致性与安全性。通过`synchronized`,我们可以控制对共享资源...

    java基本教程之synchronized关键字java多

    一、synchronized关键字的作用与原理 `synchronized`关键字主要有两个作用:同步方法和同步块。它通过锁机制来实现线程同步,防止多个线程同时执行同一段代码,可能导致的数据不一致问题。 1. 同步方法:当在方法...

    【ASP.NET编程知识】实例解析Java中的synchronized关键字与线程安全问题.docx

    本文将深入探讨`synchronized`关键字的使用及其在实际编程中的应用。 `synchronized`可以应用于以下几种形式: 1. **synchronized 代码块**:同步代码块的形式为 `synchronized (object) { ... }`,其中`object`是...

    Java多线程synchronized关键字详解(六)共5

    本篇将详细解析`synchronized`的关键特性和使用方法,帮助开发者深入理解如何在并发编程中有效地利用这一特性。 1. **synchronized的两种使用方式** - **方法同步**:通过在方法声明前加上`synchronized`关键字,...

    深入理解java中的synchronized关键字

    本文将深入探讨`synchronized`的两种主要用法:synchronized方法和synchronized块。 1. **synchronized 方法** synchronized方法是通过在方法声明前添加`synchronized`关键字来定义的。例如: ```java public ...

    【多线程与高并发原理篇:4_深入理解synchronized】.doc

    【深入理解synchronized】 在Java多线程编程中,`synchronized`关键字是实现线程安全的关键工具之一,它提供了一种同步机制,确保共享资源在同一时间只能被一个线程访问。本文将从应用层、字节码层面和Java虚拟机...

    Java 多线程synchronized关键字详解(六)

    在这个问题中,我们将深入理解`synchronized`的关键字用法,包括同步方法和同步块。 1. **同步方法**: 当`synchronized`关键字修饰一个方法时,这个方法称为同步方法。这意味着当一个线程进入这个方法时,它会...

    java基本教程之synchronized关键字 java多线程教程

    理解并正确使用synchronized关键字是Java多线程编程的关键,它可以帮助开发者防止数据不一致性和线程竞态条件,确保多线程环境下的数据安全。然而,过度使用synchronized可能导致性能下降,因此需要根据具体应用场景...

    Java中synchronized正确使用方法解析

    本文将详细介绍 Java 中 synchronized 的正确使用方法,通过示例代码和实践案例,帮助读者深入理解 synchronized 的使用方法和原理。 一、并行和锁 并行是一种提高程序效率的方式,它允许多个线程同时执行,提高...

    java 面试

    4. **多线程**:了解线程的创建(Thread类、Runnable接口)、同步机制(synchronized关键字、wait()、notify()、notifyAll()方法)、线程池(ExecutorService、ThreadPoolExecutor)以及并发工具类(Semaphore、...

    实例解析Java中的synchronized关键字与线程安全问题

    在Java编程语言中,`synchronized`关键字是用于处理多线程环境下的线程安全问题的关键工具。...在处理线程安全问题时,不仅要理解`synchronized`的工作原理,还要深入理解Java内存模型和并发编程的最佳实践。

    locks框架_ReentrantLock.pdf

    这份资源旨在详细讲解 Java 中的 Locks 框架,特别关注 ReentrantLock 的使用和原理。...通过这份资源,您将获得关于 Locks 框架和 ReentrantLock 的深入理解,从基本用法到高级功能,从对比分析到最佳实践。

    关于synchronized、Lock的深入理解

    众所周知,synchronized锁是JAVA的关键字,按理说是JAVA语言内置的特性,那为什么还要使用Lock呢 我们先说一说synchronized,当一个方法或者代码块被synchronized修饰,并执行到此方法或者代码块时,获取到锁并执行...

    Android synchronized 测试案例

    本测试案例深入探讨了`synchronized`的使用方法,包括同步单个对象、同步多个对象以及成功与失败的场景对比。 一、`synchronized`关键字的基本概念 `synchronized`关键字可以修饰方法或用作代码块,其主要作用是...

    Synchronized_思维导图(全面).xmind.zip

    synchronized方法是通过在方法声明前加上synchronized关键字来实现的,而synchronized块则是在代码块前加上关键字,指定一个监视器对象,只有获取到该对象锁的线程才能执行该代码块。 在Java 6之后,synchronized...

    java面试题高级, 对底层高并发深入理解

    重点理解synchronized关键字、volatile变量、Lock接口(如ReentrantLock)以及Atomic类在多线程环境中的应用。 3. **并发控制**:熟悉线程同步机制,如wait()、notify()和notifyAll(),以及如何使用这些方法来实现...

    synchronized枷锁实例

    本文将深入探讨`synchronized`关键字的用法,包括类锁、对象锁、方法锁以及它们之间的关系。 **类锁(Class Lock)** 类锁是通过类的Class对象实现的,当一个线程访问类的静态 synchronized 方法或同步代码块时,就...

    第四节(Lock关键字用法)

    在深入理解`Lock`关键字的用法之前,我们先来了解一些多线程的基础知识。 多线程是现代计算机程序设计中的一个关键特性,它允许程序同时执行多个任务,从而提高资源利用率和程序性能。在Java中,创建和管理线程主要...

    深入理解Java内存模型 pdf 超清版

    - 同步块/同步方法(使用`synchronized`关键字) - 使用`Lock`接口及其实现(如`ReentrantLock`) - 线程局部变量(`ThreadLocal`) 8. **线程状态转换** - 新建(New)、就绪(Runnable)、运行(Running)、...

Global site tag (gtag.js) - Google Analytics