`

Java中synchronized 用在实例方法和对象方法上面的区别

阅读更多

        在Java中,synchronized 是用来表示同步的,我们可以synchronized 来修饰一个方法。也可以synchronized 来修饰方法里面的一个语句块。

      修饰实例方法:

public synchronized void normalMethod() throws InterruptedException {
	for (int i = 0; i < 10; i++) {
		Thread.sleep(1000);
		System.out.println("normalMethod:" + i);
	}
}

      修饰类方法(static 方法):

public static synchronized void staticMethod() throws InterruptedException {
	for (int i = 0; i < 10; i++) {
		Thread.sleep(500);
		System.out.println("staticMethod:" + i);
	}
}

       修饰方法里面语句块:

public static void staticMethod() throws InterruptedException  {  
        synchronized (locks) {  
            for (int i = 0; i < 10; i++)  {  
                Thread.sleep(1000);  
                System.out.println("staticMethod:" + i);  
           }  
       }  
}  

      注意:这里不能用synchronized修饰方法外面的语句块(我把他叫做类语句块),虽然我们可以在方法外面定义语句块,这样做会遇到编译错误,这里涉及到了Java里面的对象初始化的部分知识。大概的原因就是synchronized锁住的是对象,当初始化对象的时候,JVM在对象初始化完成之前会调用方法外面的语句块,这个时候对象还不存在,所以就不存在锁了。

      那么,在static方法和非static方法前面加synchronized到底有什么不同呢?

      static的方法属于类方法,它属于这个Class(注意:这里的Class不是指Class的某个具体对象),那么static获取到的锁,就是当前调用这个方法的对象所属的类(Class,而不再是由这个Class产生的某个具体对象了)。而非static方法获取到的锁,就是当前调用这个方法的对象的锁了。所以,他们之间不会产生互斥。

      实例1:

package com.bijian.thread;

public class SynchronizedTest {

	public static synchronized void staticMethod() throws InterruptedException {
		for (int i = 0; i < 10; i++) {
			Thread.sleep(500);
			System.out.println("staticMethod:" + i);
		}
	}

	public synchronized void normalMethod() throws InterruptedException {
		for (int i = 0; i < 10; i++) {
			Thread.sleep(1000);
			System.out.println("normalMethod:" + i);
		}
	}

	public static void main(String[] args) {
		final SynchronizedTest synchronizedTest = new SynchronizedTest();
		Thread thread = new Thread(new Runnable() {
			public void run() {
				try {
					synchronizedTest.normalMethod();
				} catch (InterruptedException e) {
					e.printStackTrace();
				}
			}
		}, "a");

		Thread thread1 = new Thread(new Runnable() {
			public void run() {
				try {
					SynchronizedTest.staticMethod();
				} catch (InterruptedException e) {
					e.printStackTrace();
				}
			}
		}, "b");

		thread1.start();
		thread.start();
	}
}

       运行结果:

staticMethod:0
normalMethod:0
staticMethod:1
staticMethod:2
normalMethod:1
staticMethod:3
staticMethod:4
normalMethod:2
staticMethod:5
staticMethod:6
normalMethod:3
staticMethod:7
staticMethod:8
normalMethod:4
staticMethod:9
normalMethod:5
normalMethod:6
normalMethod:7
normalMethod:8
normalMethod:9

       那当我们想让所有这个类下面的对象都同步的时候,也就是让所有这个类下面的对象共用同一把锁的时候,我们如何办呢?

       法1:将normalMethod方法也改成static,这样这两个static方法都属于类方法,它们获取到的锁都是当前调用这个方法的对象所属的类(Class,而不再是由这个Class产生的某个具体对象了)。但这样会影响代码结构和对象的封装性。

       修改实例1如下:

package com.bijian.thread;

public class SynchronizedTest {
	public static synchronized void staticMethod() throws InterruptedException {
		for (int i = 0; i < 10; i++) {
			Thread.sleep(500);
			System.out.println("staticMethod:" + i);
		}
	}
	public static synchronized void normalMethod() throws InterruptedException {
		for (int i = 0; i < 10; i++) {
			Thread.sleep(1000);
			System.out.println("normalMethod:" + i);
		}
	}

	public static void main(String[] args) {
		Thread thread = new Thread(new Runnable() {
			public void run() {
				try {
					SynchronizedTest.normalMethod();
				} catch (InterruptedException e) {
					e.printStackTrace();
				}
			}
		}, "a");
		
		Thread thread1 = new Thread(new Runnable() {
			public void run() {
				try {
					SynchronizedTest.staticMethod();
				} catch (InterruptedException e) {
					e.printStackTrace();
				}
			}
		}, "b");

		thread1.start();
		thread.start();
	}
}

       运行结果:

staticMethod:0
staticMethod:1
staticMethod:2
staticMethod:3
staticMethod:4
staticMethod:5
staticMethod:6
staticMethod:7
staticMethod:8
staticMethod:9
normalMethod:0
normalMethod:1
normalMethod:2
normalMethod:3
normalMethod:4
normalMethod:5
normalMethod:6
normalMethod:7
normalMethod:8
normalMethod:9

       也许有人说:将实例1的staticMethod方法改成的static去掉也能达到目的。确实可以,因为非static方法获取到的锁,就是当前调用这个方法的对象的锁,而实例1只有一个SynchronizedTest实例,如再创建一个实例,则就有问题了。如下所示:

         

package com.bijian.thread;

public class SynchronizedTest {

	public synchronized void staticMethod() throws InterruptedException {
		for (int i = 0; i < 10; i++) {
			Thread.sleep(500);
			System.out.println("staticMethod:" + i);
		}
	}

	public synchronized void normalMethod() throws InterruptedException {
		for (int i = 0; i < 10; i++) {
			Thread.sleep(1000);
			System.out.println("normalMethod:" + i);
		}
	}

	public static void main(String[] args) {
		final SynchronizedTest synchronizedTest = new SynchronizedTest();
		Thread thread = new Thread(new Runnable() {
			public void run() {
				try {
					synchronizedTest.normalMethod();
				} catch (InterruptedException e) {
					e.printStackTrace();
				}
			}
		}, "a");

		//为了验证获取到的锁都是当前调用这个方法的对象所属的类,特另新建一个对象
		final SynchronizedTest synchronizedTest2 = new SynchronizedTest();
		
		Thread thread1 = new Thread(new Runnable() {
			public void run() {
				try {
					synchronizedTest2.staticMethod();
				} catch (InterruptedException e) {
					e.printStackTrace();
				}
			}
		}, "b");

		thread1.start();
		thread.start();
	}
}

       运行结果:

staticMethod:0
staticMethod:1
normalMethod:0
staticMethod:2
staticMethod:3
normalMethod:1
staticMethod:4
staticMethod:5
normalMethod:2
staticMethod:6
normalMethod:3
staticMethod:7
staticMethod:8
normalMethod:4
staticMethod:9
normalMethod:5
normalMethod:6
normalMethod:7
normalMethod:8
normalMethod:9

 

       法2:语句块锁,直接看如下实例:

       实例2:

package com.bijian.thread;

public class SynchronizedTest {

	public final static Byte[] locks = new Byte[0];  

	public static void staticMethod() throws InterruptedException {
		synchronized(locks) {
			for (int i = 0; i < 10; i++) {
				Thread.sleep(500);
				System.out.println("staticMethod:" + i);
			}
		}
	}

	public void normalMethod() throws InterruptedException {
		synchronized(locks) {
			for (int i = 0; i < 10; i++) {
				Thread.sleep(1000);
				System.out.println("normalMethod:" + i);
			}
		}
	}

	public static void main(String[] args) {
		final SynchronizedTest synchronizedTest = new SynchronizedTest();
		Thread thread = new Thread(new Runnable() {
			public void run() {
				try {
					synchronizedTest.normalMethod();
				} catch (InterruptedException e) {
					e.printStackTrace();
				}
			}
		}, "a");

		Thread thread1 = new Thread(new Runnable() {
			public void run() {
				try {
					SynchronizedTest.staticMethod();
				} catch (InterruptedException e) {
					e.printStackTrace();
				}
			}
		}, "b");

		thread1.start();
		thread.start();
	}
}

       运行结果:

staticMethod:0
staticMethod:1
staticMethod:2
staticMethod:3
staticMethod:4
staticMethod:5
staticMethod:6
staticMethod:7
staticMethod:8
staticMethod:9
normalMethod:0
normalMethod:1
normalMethod:2
normalMethod:3
normalMethod:4
normalMethod:5
normalMethod:6
normalMethod:7
normalMethod:8
normalMethod:9
分享到:
评论

相关推荐

    synchronized用法大全实例

    - **对象锁**:如果`synchronized`修饰非静态方法或者同步语句块中的对象引用是实例引用,那么锁定的是该实例对象。例如: ```java public class MyObject { public synchronized void method() { // ... } }...

    java里面synchronized用法.doc

    在上面的例子中,synchronized 关键字被用于 myMethod 方法上,以防止多个线程同时访问同一个对象的 myMethod 方法。 2. 类范围:synchronized 关键字也可以被用于类范围内,以防止多个线程同时访问同一个类中的...

    Java synchronized使用案例

    Java中的`synchronized`关键字是多线程编程中的一个重要概念,用于控制并发访问共享资源,以保证数据的一致性和完整性。这个关键词提供了互斥锁机制,防止多个线程同时执行同一段代码,确保了线程安全。 一、`...

    Java synchronized详细解读.docx

    同步方法是通过在方法声明前加上`synchronized`关键字,例如`public synchronized void method() {...}`。同步代码块则是通过`synchronized`关键字包裹一段代码,如`synchronized (object) { ... }`,这里的`object`...

    透彻理解Java中Synchronized(对象锁)和Static Synchronized(类锁)的区别

    在上面的代码示例中,我们可以看到,Synchronized 和 Static Synchronized 的使用场景不同。Synchronized 是用于锁定当前对象的实例,而 Static Synchronized 是用于锁定该类的所有实例。 在多线程中,如果我们使用...

    [JAVA][synchronized的使用]

    总结,`synchronized`是Java中实现线程安全的关键工具,理解其工作原理和使用方式对于编写高效、安全的多线程程序至关重要。然而,在实际应用中,我们需要根据具体场景选择最合适的并发控制手段,平衡性能和安全性。

    java_synchronized详解

    通过在方法或代码块上使用`synchronized`,可以确保同一时间只有一个线程能访问这些代码区域,从而有效避免了多线程环境下的数据竞争和不一致性问题。 #### 二、synchronized的作用机制 `synchronized`主要通过对象...

    synchronized枷锁实例

    在Java编程语言中,`synchronized`关键字是一个非常重要的同步机制,用于控制多线程对共享资源的访问,以防止数据不一致性和竞态条件。本文将深入探讨`synchronized`关键字的用法,包括类锁、对象锁、方法锁以及它们...

    Java-synchronized详解.docx

    在 Account 类中,我们使用了 synchronized 来同步 deposit 和 withdraw 方法,以确保在同一时间只有一个线程可以访问这些方法。这样可以防止多个线程同时访问 Account 对象的 amount 变量,避免数据不一致和 race ...

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

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

    java synchronized demo

    在Java编程语言中,`...总结,`java synchronized demo`是一个关于如何在Java中使用`synchronized`关键字进行线程同步的示例,通过理解和实践这个例子,开发者可以更好地掌握多线程环境下数据安全和同步的重要性。

    《Java面向对象编程》实例源代码

    《Java面向对象编程》实例源代码是一份宝贵的教育资源,它涵盖了Java编程中面向对象的核心概念。这份资源由知名教育机构飞思出品,旨在帮助学习者深入理解和应用面向对象编程技术。通过这些源代码实例,我们可以深入...

    深入理解java中的synchronized关键字

    Java中的`synchronized`关键字是用于实现线程同步的关键机制,它的主要目的是确保在多线程环境中,对共享资源的访问能够保持数据的一致性和完整性。本文将深入探讨`synchronized`的两种主要用法:synchronized方法和...

    java-synchronized详解.doc

    本文将深入解析`synchronized`在Java中的应用和工作原理。 一、`synchronized`的基本用法 `synchronized`可以应用于方法或代码块。当它修饰一个方法时,整个方法被视为同步的,只有一个线程可以执行该方法。当修饰...

    Java使用synchronized修饰方法来同步线程的实例演示

    本文将深入探讨synchronized修饰方法在Java中的使用及其工作原理,并通过实例演示其应用。 1. **synchronized原理** synchronized基于Java的内置锁(也称为对象锁或 monitors)机制。当一个线程进入synchronized...

    Android synchronized 测试案例

    1. 同步方法:在方法声明前加上`synchronized`关键字,使得每次只有一个线程能执行该方法。 ```java public synchronized void method() { // 方法体 } ``` 2. 同步代码块:锁定对象实例,只允许一个线程访问指定的...

    Java 同步锁(synchronized)详解及实例

    在售票示例中,我们可以用`this`作为监视器对象,因为它代表当前类的实例: ```java public void run() { for (int i = 0; i ; i++) { if (this.ticket &gt; 0) { synchronized (this) { // 休眠1s try { ...

    Java多线程程序中synchronized修饰方法的使用实例

    本篇将深入探讨`synchronized`修饰方法在Java多线程程序中的使用实例。 1. **同步方法** 同步方法是通过在方法声明前加上`synchronized`关键字来实现的。当一个方法被声明为同步时,意味着在同一时刻只有一个线程...

    java synchronized详解

    Java中的`synchronized`关键字是多线程编程中的一个重要概念,用于控制并发访问共享资源,确保数据的正确性和一致性。在Java中,同步可以应用于方法或代码块,为线程提供互斥访问,防止数据竞争问题。 1. **什么是`...

    java synchronized 学习

    Java 中的 synchronized 关键字是用来实现线程同步的,它可以用来修饰方法、代码块和静态方法,以确保在多线程环境下数据的一致性。 一、进程和线程的区别 在计算机中,每个运行着的 xxxx.exe 都是一个进程,而...

Global site tag (gtag.js) - Google Analytics