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

news/2024/5/17 20:21:47 标签: java, 多线程, synchronized

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

      修饰实例方法:

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

      修饰类方法(static 方法):

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

       修饰方法里面语句块:

java">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:

java">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如下:

java">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实例,如再创建一个实例,则就有问题了。如下所示:

         

java">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:

java">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

http://www.niftyadmin.cn/n/1319134.html

相关文章

android的一些特殊玩法

1.让一个图片透明&#xff1a; 复制到剪贴板 Java代码 1. Bitmap buffer Bitmap.createBitmap(width, border"1" Height, Bitmap.Config.ARGB_4444);buffer.eraseColor(Color.TRANSPARENT); 2.直接发送邮件&#xff1a; 复制到剪贴板 Java代码 1. Intent intent ne…

react-native 找不到符号问题的解决方案

最近&#xff08;2022年11月4日&#xff09;很多 react-native 项目上都出现了打包失败或者是开发环境无法启动的问题&#xff0c;报错内容很多&#xff1a;找不到符号、方法不会覆盖或者实现超类型的方法、程序包 XXX 不存在等。但点进源码可以发现几乎都是 com.facebook.reac…

java的wait与notify

wait与notify是java同步机制中重要的组成部分。结合与synchronized关键字使用&#xff0c;可以建立很多优秀的同步模型。 synchronized(this){}等价与public synchronized void method(){.....} 同步分为类级别和对象级别&#xff0c;分别对应着类锁和对象锁。类锁是每个类只有…

spring.net之aop加单例模式编写无try catch程序

为应付软件小白的各种无脑操作&#xff08;不过话说回来&#xff0c;软件就是给小白使用的&#xff09;&#xff0c;常常需要在调用方法时增加众多重复的try/catch&#xff0c;后来拜读artech的《如何编写没有Try/Catch的程序》&#xff0c;了解到可以将try/catch统一处理&…

守护线程概念及实例

守护线程在没有用户线程可服务时自动离开&#xff0c;在Java中比较特殊的线程是被称为守护&#xff08;Daemon&#xff09;线程的低级别线程。这个线程具有最低的优先级&#xff0c;用于为系统中的其它对象和线程提供服务。 将一个用户线程设置为守护线程的方式是在线程对象创建…

Android学习链接大放送

虽然贴链接这种事情。。真是一种很偷懒的做法。。。 但是我一个小菜鸟&#xff0c;果断还是要以多向别人学习为主。。。 好资源要和大家分享对不对&#xff01; 况且。。放博客里。。比收藏夹的利用几率要大一点&#xff01; 原作者应该也很喜欢我这种贴链接打广告的做法吧。。…

java.sql.SQLException: ORA-01461: can bfor insert into a LONG column问题分析与小结

java.sql.SQLException: ORA-01461: can bfor insert into a LONG column 1.发现系统报此问题的第一反应是插入数据时&#xff0c;数据长度超出数据库的字段长度。 2.而根据错误日志不难分析出是向邮件发送信息表中插入数据时&#xff0c;数据超过定义的最大值限制了&#xff0…

python tips - 静态方法和类成员方法

摘自 《Python 基础教程》 9.5.2 静态方法和类成员方法 p149 在讨论实现属性的旧方法前&#xff0c;先让我们绕道而行&#xff0c;看看另一对实现方法和新式属性的实现方法类似的特征。静态方法和类成员方法分别在创建时被装入Staticmethod类型和Classmethod类型的对象中。…