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. html2canvas用法的总结(转载)

    最近做h5网页,有个功能是用户能长按页面保存为图片,在我们理解就是网页要生成图片然后再让用户长按保存,然后就发现了html2canvas这个框架了,效果挺不错了,但是有几个坑说一下(用的最新版): h ...

  2. struts2 中的数据访问servletAPI

    ActionContext包含其他数据对象,包括值栈     每次请求都会创建一个ActionContext对象 通过ActionContext访问数据 在action中读取  在jsp页面中读取 1 ...

  3. DevExpress Cpicturebox或者Dev控件 PictureEdit 按比例的缩放加载图片

    方法一:     如果要加载的图片的长宽比不是太过失衡, 1.可以改变picturebox的SizeMode属性为 PictureBoxSizeMode.StretchImage, 2.或者Dev控件 ...

  4. [转]分布式系统唯一ID生成方案汇总

    系统唯一ID是我们在设计一个系统的时候常常会遇见的问题,也常常为这个问题而纠结.生成ID的方法有很多,适应不同的场景.需求以及性能要求.所以有些比较复杂的系统会有多个ID生成的策略.下面就介绍一些常见 ...

  5. node 各模块及对应功能

    node 各模块及对应功能 node 模块 对应功能 net 处理 TCP dgram 处理 UDP http 处理 HTTP/1 http2 处理 HTTP/2 https 处理 HTTPS tls ...

  6. ts项目报错:Import sources within a group must be alphabetized

    报错:Import sources within a group must be alphabetized. 原因:import名称排序问题,要求按照字母从小到大排序:修改 tslint.json 中 ...

  7. laravel 获取上一条insert语句产生的id

    <?php //頭部引入DB類 use Illuminate\Support\Facades\DB; //在方法中獲取获取上一条insert语句产生的id $id = DB::getPdo()- ...

  8. PyCharm 链接MySQL 数据库

    1.View -> Tool Windows-Database; 2.添加数据源: 3.配置数据库的驱动信息: 4.设置驱动文件,勾选“Use Provided driver MySQL Con ...

  9. RedHat7局域网下安装离线Ambari

    1 Ambari介绍.安装与应用案例介绍 1.1 Ambari Ambari 跟 Hadoop 等开源软件一样,也是 Apache Software Foundation 中的一个项目,并且是顶级项目 ...

  10. mongodb morphia删除数组中指定条件的数据

    先看mongodb操作: db.test.update({"msgid":170},{"$pull":{"msg":{"comti ...