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. 【BZOJ2019】nim

    直播写题这刺激233 原题: 著名游戏设计师vfleaking,最近迷上了Nim.普通的Nim游戏为:两个人进行游戏,N堆石子,每回合可以取其中某一堆的任意多个,可以取完,但不可以不取.谁不能取谁输. ...

  2. linux环境下配置mysql双主复制

    简单来说,双主复制就是让两台mysql服务器中的数据保持同步,可以用来实现灾备和负载均衡 主机1 IP:192.168.200.128 主机2 IP:192.168.200.131 两台主机系统均为c ...

  3. skipper 内置的常用filters

    skipper 的filter 功能很强大,可做好多方便的扩展 格式: all: * -> filter1 -> filter2 -> "http://127.0.0.1: ...

  4. Java各个知识点详解总结

    Java基础知识总结 写代码: 1,明确需求.我要做什么? 2,分析思路.我要怎么做?1,2,3. 3,确定步骤.每一个思路部分用到哪些语句,方法,和对象. 4,代码实现.用具体的java语言代码把思 ...

  5. 对某个区间操作(sort,stable_sort,parital_sort,parital_sort_copy,nth_element,is_sorted)

    sort //版本一 template <class RandomAccessIterator> void sort(RandomAccessIterator first,RandomAc ...

  6. Spring Boot 历史

    2012年10月,Mike Youngstrom在Spring jira中创建了一个功能需求,要求在Spring框架中支持无容器Web应用程序体系结构.他建议通过main方法引导的Spring容器内配 ...

  7. mongodb之 3.4.0 mongodb sharing 副本集群搭建

    系统系统 centos6.5三台服务器:10.100.25.42/43/44安装包: mongodb-linux-x86_64-rhel62-3.4.0.tgz 服务器规划:mongos mongos ...

  8. spring-IOC容器(三)

    一.通过工厂方法配置Bean: .xml <!-- class属性:指向静态工厂方法的全类名 factory-method:指向静态工厂方法的名字 constructor-arg:如果工厂方法需 ...

  9. C#:单元测试(VS2015)

    根据VS2015的提示,仅支持在共有类或共有方法中支持创建单元测试.所以,如果我们要测试私有或是保护的类和方法,是要先将他们暂时设定成公有类型. 在VS2015中创建单元测试,只要在我们想测试的地方点 ...

  10. Apache Kafka监控之KafkaOffsetMonitor

    转载自:http://www.cnblogs.com/Leo_wl/p/4564699.html 1.概述 前面给大家介绍了Kafka的背景以及一些应用场景,并附带上演示了Kafka的简单示例.然后, ...