Java中可以使用关键字synchronized进行线程同步控制,实现关键资源顺序访问,避免由于多线程并发执行导致的数据不一致性等问题。synchronized的原理是对象监视器(锁),只有获取到监视器的线程才能继续执行,否则线程会等待获取监视器。Java中每个对象或者类都有一把锁与之相关联,对于对象来说,监视的是这个对象的实例变量,对于类来说,监视的是类变量(一个类本身是类Class的对象,所以与类关联的锁也是对象锁)。synchronized关键字使用方式有两种:synchronized方法和synchronized块。这两种监视区域都和一个引入对象相关联,当到达这个监视区域时,JVM就会锁住这个引用对象,当离开时会释放这个引用对象上的锁(有异常退出时,JVM会释放锁)。对象锁是JVM内部机制,只需要编写同步方法或者同步块即可,操作监视区域时JVM会自动获取锁或者释放锁。

首先来看同步方法的例子:

public class SynchronizedTest1 extends Thread
{private synchronized void testSynchronizedMethod(){for (int i = 0; i < 10; i++){System.out.println(Thread.currentThread().getName()+ " testSynchronizedMethod:" + i);try{Thread.sleep(100);}catch (InterruptedException e){e.printStackTrace();}}}@Overridepublic void run(){testSynchronizedMethod();}public static void main(String[] args){SynchronizedTest1 t = new SynchronizedTest1();t.start();t.testSynchronizedMethod();}
}

运行该程序输出结果为:

main testSynchronizedMethod:0
main testSynchronizedMethod:1
main testSynchronizedMethod:2
main testSynchronizedMethod:3
main testSynchronizedMethod:4
main testSynchronizedMethod:5
main testSynchronizedMethod:6
main testSynchronizedMethod:7
main testSynchronizedMethod:8
main testSynchronizedMethod:9
Thread-0 testSynchronizedMethod:0
Thread-0 testSynchronizedMethod:1
Thread-0 testSynchronizedMethod:2
Thread-0 testSynchronizedMethod:3
Thread-0 testSynchronizedMethod:4
Thread-0 testSynchronizedMethod:5
Thread-0 testSynchronizedMethod:6
Thread-0 testSynchronizedMethod:7
Thread-0 testSynchronizedMethod:8
Thread-0 testSynchronizedMethod:9

可以看到testSynchronizedMethod方法在两个线程之间同步执行。

如果此时将main方法修改为如下所示,则两个线程并不能同步执行,因为此时两个线程的同步监视器不是同一个对象,不能起到同步的作用。

public static void main(String[] args){Thread t = new SynchronizedTest1();t.start();Thread t1 = new SynchronizedTest1();t1.start();}

此时输出结果如下所示:

Thread-0 testSynchronizedMethod:0
Thread-1 testSynchronizedMethod:0
Thread-0 testSynchronizedMethod:1
Thread-1 testSynchronizedMethod:1
Thread-0 testSynchronizedMethod:2
Thread-1 testSynchronizedMethod:2
Thread-0 testSynchronizedMethod:3
Thread-1 testSynchronizedMethod:3
Thread-0 testSynchronizedMethod:4
Thread-1 testSynchronizedMethod:4
Thread-0 testSynchronizedMethod:5
Thread-1 testSynchronizedMethod:5
Thread-0 testSynchronizedMethod:6
Thread-1 testSynchronizedMethod:6
Thread-0 testSynchronizedMethod:7
Thread-1 testSynchronizedMethod:7
Thread-0 testSynchronizedMethod:8
Thread-1 testSynchronizedMethod:8
Thread-0 testSynchronizedMethod:9
Thread-1 testSynchronizedMethod:9

若想修改后的main方法能够在两个线程之间同步运行,需要将testSynchronizedMethod方法声明为静态方法,这样两个线程的监视器是同一个对象(类对象),能够同步执行。修改后的代码如下所示:

public class SynchronizedTest1 extends Thread
{private static synchronized void testSynchronizedMethod(){for (int i = 0; i < 10; i++){System.out.println(Thread.currentThread().getName()+ " testSynchronizedMethod:" + i);try{Thread.sleep(100);}catch (InterruptedException e){e.printStackTrace();}}}@Overridepublic void run(){testSynchronizedMethod();}public static void main(String[] args){Thread t = new SynchronizedTest1();t.start();Thread t1 = new SynchronizedTest1();t1.start();}
}

输出结果如下:

Thread-0 testSynchronizedMethod:0
Thread-0 testSynchronizedMethod:1
Thread-0 testSynchronizedMethod:2
Thread-0 testSynchronizedMethod:3
Thread-0 testSynchronizedMethod:4
Thread-0 testSynchronizedMethod:5
Thread-0 testSynchronizedMethod:6
Thread-0 testSynchronizedMethod:7
Thread-0 testSynchronizedMethod:8
Thread-0 testSynchronizedMethod:9
Thread-1 testSynchronizedMethod:0
Thread-1 testSynchronizedMethod:1
Thread-1 testSynchronizedMethod:2
Thread-1 testSynchronizedMethod:3
Thread-1 testSynchronizedMethod:4
Thread-1 testSynchronizedMethod:5
Thread-1 testSynchronizedMethod:6
Thread-1 testSynchronizedMethod:7
Thread-1 testSynchronizedMethod:8
Thread-1 testSynchronizedMethod:9

同步块的情况与同步方法类似,只是同步块将同步控制的粒度缩小,这样能够更好的发挥多线程并行执行的效率。
使用this对象控制同一对象实例之间的同步:

public class SynchronizedTest2 extends Thread
{private void testSynchronizedBlock(){synchronized (this){for (int i = 0; i < 10; i++){System.out.println(Thread.currentThread().getName()+ " testSynchronizedBlock:" + i);try{Thread.sleep(100);}catch (InterruptedException e){e.printStackTrace();}}}}@Overridepublic void run(){testSynchronizedBlock();}public static void main(String[] args){SynchronizedTest2 t = new SynchronizedTest2();t.start();t.testSynchronizedBlock();}
}

输出结果:

main testSynchronizedBlock:0
main testSynchronizedBlock:1
main testSynchronizedBlock:2
main testSynchronizedBlock:3
main testSynchronizedBlock:4
main testSynchronizedBlock:5
main testSynchronizedBlock:6
main testSynchronizedBlock:7
main testSynchronizedBlock:8
main testSynchronizedBlock:9
Thread-0 testSynchronizedBlock:0
Thread-0 testSynchronizedBlock:1
Thread-0 testSynchronizedBlock:2
Thread-0 testSynchronizedBlock:3
Thread-0 testSynchronizedBlock:4
Thread-0 testSynchronizedBlock:5
Thread-0 testSynchronizedBlock:6
Thread-0 testSynchronizedBlock:7
Thread-0 testSynchronizedBlock:8
Thread-0 testSynchronizedBlock:9

使用class对象控制不同实例之间的同步:

public class SynchronizedTest2 extends Thread
{private void testSynchronizedBlock(){synchronized (SynchronizedTest2.class){for (int i = 0; i < 10; i++){System.out.println(Thread.currentThread().getName()+ " testSynchronizedBlock:" + i);try{Thread.sleep(100);}catch (InterruptedException e){e.printStackTrace();}}}}@Overridepublic void run(){testSynchronizedBlock();}public static void main(String[] args){Thread t = new SynchronizedTest2();t.start();Thread t2 = new SynchronizedTest2();t2.start();}
}

输出结果:

Thread-0 testSynchronizedBlock:0
Thread-0 testSynchronizedBlock:1
Thread-0 testSynchronizedBlock:2
Thread-0 testSynchronizedBlock:3
Thread-0 testSynchronizedBlock:4
Thread-0 testSynchronizedBlock:5
Thread-0 testSynchronizedBlock:6
Thread-0 testSynchronizedBlock:7
Thread-0 testSynchronizedBlock:8
Thread-0 testSynchronizedBlock:9
Thread-1 testSynchronizedBlock:0
Thread-1 testSynchronizedBlock:1
Thread-1 testSynchronizedBlock:2
Thread-1 testSynchronizedBlock:3
Thread-1 testSynchronizedBlock:4
Thread-1 testSynchronizedBlock:5
Thread-1 testSynchronizedBlock:6
Thread-1 testSynchronizedBlock:7
Thread-1 testSynchronizedBlock:8
Thread-1 testSynchronizedBlock:9

使用synchronized关键字进行同步控制时,一定要把握好对象监视器,只有获得监视器的进程可以运行,其它都需要等待获取监视器。任何一个非null的对象都可以作为对象监视器,当synchronized作用在方法上时,锁住的便是对象实例(this);当作用在静态方法时锁住的便是对象对应的Class实例。

总结:

synchronized是通过软件(JVM)实现的,简单易用,即使在JDK5之后有了Lock,仍然被广泛地使用。
synchronized实际上是非公平的,新来的线程有可能立即获得监视器,而在等待区中等候已久的线程可能再次等待,不过这种抢占的方式可以预防饥饿。
synchronized只有锁只与一个条件(是否获取锁)相关联,不灵活,后来Condition与Lock的结合解决了这个问题。
多线程竞争一个锁时,其余未得到锁的线程只能不停的尝试获得锁,而不能中断。高并发的情况下会导致性能下降。ReentrantLock的lockInterruptibly()方法可以优先考虑响应中断。 一个线程等待时间过长,它可以中断自己,然后ReentrantLock响应这个中断,不再让这个线程继续等待。有了这个机制,使用ReentrantLock时就不会像synchronized那样产生死锁了。

参考资料:

JAVA并发编程学习笔记之synchronized
深入JVM锁机制1-synchronized

java 对象锁

Java同步之synchronized相关推荐

  1. Java同步锁Synchronized底层源码和原理剖析

    目录 1 synchronized场景回顾 2 反汇编寻找锁实现原理 3 synchronized虚拟机源码 3.1 HotSpot源码Monitor生成 3.2 HotSpot源码之Monitor竞 ...

  2. java同步机制:synchronized

    在Java中,synchronized关键字是用来控制线程同步的,就是在多线程的环境下,控制synchronized代码段不被多个线程同时执行.synchronized既可以加在一段代码上,也可以加在 ...

  3. java同步锁synchronized_Java对象锁和类锁全面解析(多线程synchronized关键字)

    本文主要是将synchronized关键字用法作为例子来去解释Java中的对象锁和类锁.特别的是希望能帮大家理清一些概念. 一.synchronized关键字 synchronized关键字有如下两种 ...

  4. Java线程同步:synchronized锁住的是代码还是对象

    在Java中,synchronized关键字是用来控制线程同步的,就是在多线程的环境下,控制synchronized代码段不被多个线程同时执行.synchronized既可以加在一段代码上,也可以加在 ...

  5. java同步关键词解释、synchronized、线程锁(Lock)

    1.java同步关键词解释 21.1 synchronized synchronized是用来实现线程同步的!!! 加同步格式: synchronized( 需要一个任意的对象(锁) ){ 代码块中放 ...

  6. java 同步块_java 同步块(Java Synchronized Blocks)

    java 同步块(Java Synchronized Blocks) Java 同步块包括方法同步和代码块同步.java 同步可以避免资源竞争,避免死锁. 主题包括的主要内容: The Java sy ...

  7. 四、java多线程核心技术——synchronized同步方法与synchronized同步快

    一.synchronized同步方法 论:"线程安全"与"非线程安全"是多线程的经典问题.synchronized()方法就是解决非线程安全的. 1.方法内的变 ...

  8. java 同步块(Java Synchronized Blocks)

    java 同步块(Java Synchronized Blocks) Java 同步块包括方法同步和代码块同步.java 同步可以避免资源竞争,避免死锁. 主题包括的主要内容: synchronize ...

  9. 【线程同步】 Java 同步块(synchronized)详细说明

    我们在java开发中常常用synchronized( 互斥锁)来进行同步,但是对于 synchronized关键字有那些用法,会产生什么样的效果却不一定清楚,下面将详细介绍synchronized在程 ...

最新文章

  1. 4-2 ADO.NET-查询和检索数据5
  2. hbase组合rowkey_「从零单排HBase 11」HBase二级索引解决方案
  3. 如何优雅地「蜗居」?
  4. Hadoop集群(第10期副刊)_常用MySQL数据库命令
  5. 【 D3.js 入门系列 --- 7 】 理解 update, enter, exit 的使用
  6. XML的概述,.Dom4解析和SAX解析
  7. C语言书籍推荐从入门到进阶再到封神全套(2021年整理)
  8. httpd2.4.39直接访问路径下的ceb文件,显示乱码
  9. vscode鼠标滚轮调整字体大小
  10. ME525+ 刷机工具及设置中心号码
  11. linux查看隐藏大文件夹,Linux系统隐藏文件/文件夹操作教程
  12. Kettle 全量抽取数据
  13. 【AI Studio】飞桨图像分类零基础训练营 - 03 - 卷积神经网络基础
  14. omi html转义,特殊字符读法
  15. 【UV打印机】PrintExp打印软件教程(五)-高级
  16. 网页视频播放插件ckplayer的使用-详细介绍
  17. R 实战 | 使用clusterProfiler进行多组基因富集分析
  18. #10038.A Horrible Poem
  19. 办理3C认证多少钱?包含哪些费用?
  20. 致远项目管理SPM系统案例:道道全粮油股份有限公司人力资源管理

热门文章

  1. vmware_无法连接虚拟机vmx提前退出
  2. 动态图 vs 静态图
  3. OPENGL-学习计算机图形学
  4. 如何做好一个IT项目经理? (一)
  5. 天龙八部元宝兑换代码
  6. 群体遗传 | haplotype block | HaploBlocker参数介绍
  7. 2021最新css3面试题理论,前端css面试题,移动端面试题理论。
  8. 计算机辅助普通话水平测试应试手册,普通话水平测试应试手册
  9. 配置PHP运行环境的方法步骤
  10. 云仓代发货到底是什么?