https://bijian1013.iteye.com/blog/1836575

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

修饰实例方法:

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

修饰类方法(static 方法):

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

修饰方法里面语句块:

  1. public static void staticMethod() throws InterruptedException  {
  2. synchronized (locks) {
  3. for (int i = 0; i < 10; i++)  {
  4. Thread.sleep(1000);
  5. System.out.println("staticMethod:" + i);
  6. }
  7. }
  8. }

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

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

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

实例1:

  1. package com.bijian.thread;
  2. public class SynchronizedTest {
  3. public static synchronized void staticMethod() throws InterruptedException {
  4. for (int i = 0; i < 10; i++) {
  5. Thread.sleep(500);
  6. System.out.println("staticMethod:" + i);
  7. }
  8. }
  9. public synchronized void normalMethod() throws InterruptedException {
  10. for (int i = 0; i < 10; i++) {
  11. Thread.sleep(1000);
  12. System.out.println("normalMethod:" + i);
  13. }
  14. }
  15. public static void main(String[] args) {
  16. final SynchronizedTest synchronizedTest = new SynchronizedTest();
  17. Thread thread = new Thread(new Runnable() {
  18. public void run() {
  19. try {
  20. synchronizedTest.normalMethod();
  21. } catch (InterruptedException e) {
  22. e.printStackTrace();
  23. }
  24. }
  25. }, "a");
  26. Thread thread1 = new Thread(new Runnable() {
  27. public void run() {
  28. try {
  29. SynchronizedTest.staticMethod();
  30. } catch (InterruptedException e) {
  31. e.printStackTrace();
  32. }
  33. }
  34. }, "b");
  35. thread1.start();
  36. thread.start();
  37. }
  38. }

运行结果:

  1. staticMethod:0
  2. normalMethod:0
  3. staticMethod:1
  4. staticMethod:2
  5. normalMethod:1
  6. staticMethod:3
  7. staticMethod:4
  8. normalMethod:2
  9. staticMethod:5
  10. staticMethod:6
  11. normalMethod:3
  12. staticMethod:7
  13. staticMethod:8
  14. normalMethod:4
  15. staticMethod:9
  16. normalMethod:5
  17. normalMethod:6
  18. normalMethod:7
  19. normalMethod:8
  20. normalMethod:9

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

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

修改实例1如下:

  1. package com.bijian.thread;
  2. public class SynchronizedTest {
  3. public static synchronized void staticMethod() throws InterruptedException {
  4. for (int i = 0; i < 10; i++) {
  5. Thread.sleep(500);
  6. System.out.println("staticMethod:" + i);
  7. }
  8. }
  9. public static synchronized void normalMethod() throws InterruptedException {
  10. for (int i = 0; i < 10; i++) {
  11. Thread.sleep(1000);
  12. System.out.println("normalMethod:" + i);
  13. }
  14. }
  15. public static void main(String[] args) {
  16. Thread thread = new Thread(new Runnable() {
  17. public void run() {
  18. try {
  19. SynchronizedTest.normalMethod();
  20. } catch (InterruptedException e) {
  21. e.printStackTrace();
  22. }
  23. }
  24. }, "a");
  25. Thread thread1 = new Thread(new Runnable() {
  26. public void run() {
  27. try {
  28. SynchronizedTest.staticMethod();
  29. } catch (InterruptedException e) {
  30. e.printStackTrace();
  31. }
  32. }
  33. }, "b");
  34. thread1.start();
  35. thread.start();
  36. }
  37. }

运行结果:

  1. staticMethod:0
  2. staticMethod:1
  3. staticMethod:2
  4. staticMethod:3
  5. staticMethod:4
  6. staticMethod:5
  7. staticMethod:6
  8. staticMethod:7
  9. staticMethod:8
  10. staticMethod:9
  11. normalMethod:0
  12. normalMethod:1
  13. normalMethod:2
  14. normalMethod:3
  15. normalMethod:4
  16. normalMethod:5
  17. normalMethod:6
  18. normalMethod:7
  19. normalMethod:8
  20. normalMethod:9

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

  1. package com.bijian.thread;
  2. public class SynchronizedTest {
  3. public synchronized void staticMethod() throws InterruptedException {
  4. for (int i = 0; i < 10; i++) {
  5. Thread.sleep(500);
  6. System.out.println("staticMethod:" + i);
  7. }
  8. }
  9. public synchronized void normalMethod() throws InterruptedException {
  10. for (int i = 0; i < 10; i++) {
  11. Thread.sleep(1000);
  12. System.out.println("normalMethod:" + i);
  13. }
  14. }
  15. public static void main(String[] args) {
  16. final SynchronizedTest synchronizedTest = new SynchronizedTest();
  17. Thread thread = new Thread(new Runnable() {
  18. public void run() {
  19. try {
  20. synchronizedTest.normalMethod();
  21. } catch (InterruptedException e) {
  22. e.printStackTrace();
  23. }
  24. }
  25. }, "a");
  26. //为了验证获取到的锁都是当前调用这个方法的对象所属的类,特另新建一个对象
  27. final SynchronizedTest synchronizedTest2 = new SynchronizedTest();
  28. Thread thread1 = new Thread(new Runnable() {
  29. public void run() {
  30. try {
  31. synchronizedTest2.staticMethod();
  32. } catch (InterruptedException e) {
  33. e.printStackTrace();
  34. }
  35. }
  36. }, "b");
  37. thread1.start();
  38. thread.start();
  39. }
  40. }

运行结果:

  1. staticMethod:0
  2. staticMethod:1
  3. normalMethod:0
  4. staticMethod:2
  5. staticMethod:3
  6. normalMethod:1
  7. staticMethod:4
  8. staticMethod:5
  9. normalMethod:2
  10. staticMethod:6
  11. normalMethod:3
  12. staticMethod:7
  13. staticMethod:8
  14. normalMethod:4
  15. staticMethod:9
  16. normalMethod:5
  17. normalMethod:6
  18. normalMethod:7
  19. normalMethod:8
  20. normalMethod:9

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

实例2:

  1. package com.bijian.thread;
  2. public class SynchronizedTest {
  3. public final static Byte[] locks = new Byte[0];
  4. public static void staticMethod() throws InterruptedException {
  5. synchronized(locks) {
  6. for (int i = 0; i < 10; i++) {
  7. Thread.sleep(500);
  8. System.out.println("staticMethod:" + i);
  9. }
  10. }
  11. }
  12. public void normalMethod() throws InterruptedException {
  13. synchronized(locks) {
  14. for (int i = 0; i < 10; i++) {
  15. Thread.sleep(1000);
  16. System.out.println("normalMethod:" + i);
  17. }
  18. }
  19. }
  20. public static void main(String[] args) {
  21. final SynchronizedTest synchronizedTest = new SynchronizedTest();
  22. Thread thread = new Thread(new Runnable() {
  23. public void run() {
  24. try {
  25. synchronizedTest.normalMethod();
  26. } catch (InterruptedException e) {
  27. e.printStackTrace();
  28. }
  29. }
  30. }, "a");
  31. Thread thread1 = new Thread(new Runnable() {
  32. public void run() {
  33. try {
  34. SynchronizedTest.staticMethod();
  35. } catch (InterruptedException e) {
  36. e.printStackTrace();
  37. }
  38. }
  39. }, "b");
  40. thread1.start();
  41. thread.start();
  42. }
  43. }

运行结果:

  1. staticMethod:0
  2. staticMethod:1
  3. staticMethod:2
  4. staticMethod:3
  5. staticMethod:4
  6. staticMethod:5
  7. staticMethod:6
  8. staticMethod:7
  9. staticMethod:8
  10. staticMethod:9
  11. normalMethod:0
  12. normalMethod:1
  13. normalMethod:2
  14. normalMethod:3
  15. normalMethod:4
  16. normalMethod:5
  17. normalMethod:6
  18. normalMethod:7
  19. normalMethod:8
  20. normalMethod:9

java中synchronized 用在实例方法和对象方法上面的区别的更多相关文章

  1. Java中synchronized用在静态方法和非静态方法上面的区别

    synchronized 修饰在 static方法和非static方法的区别   在Java中,synchronized是用来表示同步的,我们可以synchronized来修饰一个方法.也可以sync ...

  2. Java中synchronized 修饰在static方法和非static方法的区别

    [问题描述]关于Java中synchronized 用在实例方法和对象方法上面的区别 [问题分析]大家都知道,在Java中,synchronized 是用来表示同步的,我们可以synchronized ...

  3. java中synchronized的用法详解

    记下来,很重要. Java语言的关键字,当它用来修饰一个方法或者一个代码块的时候,能够保证在同一时刻最多只有一个线程执行该段代码. 一.当两个并发线程访问同一个对象object中的这个synchron ...

  4. java中synchronized的使用方法与具体解释

    Java语言的keyword.当它用来修饰一个方法或者一个代码块的时候,可以保证在同一时刻最多仅仅有一个线程运行该段代码. 一.当两个并发线程訪问同一个对象object中的这个synchronized ...

  5. Java 中 synchronized的用法详解(四种用法)

    Java语言的关键字,当它用来修饰一个方法或者一个代码块的时候,能够保证在同一时刻最多只有一个线程执行该段代码.本文给大家介绍java中 synchronized的用法,对本文感兴趣的朋友一起看看吧 ...

  6. java中 synchronized 的使用,确保异步执行某一段代码。

    最近看了个有关访问网络url和下载的例子,里面有几个synchronized的地方,系统学习下,以下内容很重要,记下来. Java语言的关键字,当它用来修饰一个方法或者一个代码块的时候,能够保证在同一 ...

  7. JAVA 中 synchronized 详解

    看到一篇关于JAVA中synchronized的用法的详解,觉得不错遂转载之..... 原文地址: http://www.cnblogs.com/GnagWang/archive/2011/02/27 ...

  8. Java中直接输出一个类的对象

    例如 package com.atguigu.java.fanshe; public class Person { String name; private int age; public Strin ...

  9. java中synchronized关键字分析

    今天我们来分析一下java中synchronized关键字.首先来看一段java代码:(本地编译环境为mac,jdk1.8的环境) Demo.java package com.example.spri ...

随机推荐

  1. lsusb

    1.lsusb查看系统的USB设备 $ lsusb Bus Device : ID : Kingston Technology Bus Device : ID 1d6b: Linux Foundati ...

  2. 修改VS2017模板文件,添加文件头部自定义注释

    找到Class.cs文件 找到VS2017安装目录下面的Class.cs文件,一般在C盘或者D盘 模块文件位置: 接口模版:C:\Program Files (x86)\Microsoft Visua ...

  3. 原生JavaScript实现跨域

    为什么需要跨域呢?这是因为我们一般的请求都是使用xhr的,但是它只能调用同一个域里面的接口,有时候,我们想要在自己的站点中调用其他站点的接口,这时候就要用到跨域了.其实,跨域并不难,我们可以通过Jav ...

  4. JAVA中通过Hibernate-Validation进行参数验证

    在开发JAVA服务器端代码时,我们会遇到对外部传来的参数合法性进行验证,而hibernate-validator提供了一些常用的参数校验注解,我们可以拿来使用.1.maven中引入hibernate- ...

  5. sql server 附加只有mdf的数据库文件

    有时候SQL Server意外断电会导致SQL Server的ldf日志文件丢失或者损坏,这个时候你如果直接附加mdf文件到SQL Server会失败,这里提供一个方法可以还原只有mdf的数据库文件, ...

  6. oracle之 AWR固定基线

    前言:可以创建AWR基线来为数据库建立已保存的工作负载视图,以便以后用来与其他AWR快照进行比较. 1. 手工创建 AWR 固定基线(固定基线如果没有设置过期时间,会永久保存) -- 根据时间创建DB ...

  7. 手动制作openstack CentOS 镜像

    https://docs.openstack.org/image-guide/centos-image.html This example shows you how to install a Cen ...

  8. bzoj 2870 最长道路tree——边分治

    题目:https://www.lydsy.com/JudgeOnline/problem.php?id=2870 关于边分治:https://www.cnblogs.com/Khada-Jhin/p/ ...

  9. 基于spring的placeholder思路处理配置信息敏感信息加密解密的实践

    基于Spring的placeholder处理思路,实现系统配置信息敏感信息的加密解密处理. 我们的处理方案,是基于类org.springframework.beans.factory.config.P ...

  10. android利用provider查询同一个数据库中没有对外暴露出来的表

    [原创]转载请加本篇博客地址http://www.cnblogs.com/scarecrow-blog/p/6266042.html 个人感觉这是android provider 的一个漏洞, 废话少 ...