分享

java程序员修炼之路线程篇四:同步

 新用户26922hFh 2022-01-09

  在上一篇文章中我跟大家聊了一下多线程引发的三个"问题",分别是竞态条件、数据竞争和缓存变量,今天我将跟大家聊一下解决这三个问题的技术:同步。

  同步是java虚拟机的一个重要特性,它能够保证多个并发的线程不会在同一时间执行同一块临界区(必须以串行方式访问的代码块)。由于线程对临界区的访问都是互斥地执行,所以这种同步属性通常称为互斥,线程取得的锁也称为互斥锁,互斥能够有效解决我在上一篇文章中提到的竞态条件和数据竞争问题。

  同步除了能够表现互斥,也能够表现可见性。可见性能确保线程在临界区执行的时候能看到共享变量最新的值,这就解决了我在上一篇文章中跟大家提到的缓存变量问题。线程进入临界区时获取主存中的变量值,在离开临界区时把新的变量值存入主存。

  同步是通过"监听器"来实现的,所谓的监听器就是针对临界区构建的并发访问控制,而并发必须是以原子的方式执行。由于每个java对象都关联一个监听器,所以线程可以通过获取和释放监听器的锁来上锁和解锁了。由于锁具备的互斥性,其中一个线程在持有监听器锁的时候,其他线程就会一直阻塞,只有当此线程离开临界区释放锁时其他线程才能获取锁。

  Java语言中使用关键字synchronized来实现对临界区的同步,有两种使用方式:一种是把synchronized放在方法的声明处,另一种是定义一个单独的synchronized块。我们先看第一种方式的实例:

  java程序员修炼之路线程篇四:同步

  这种同步方式会在进入方法区时获取锁,在方法结束后释放锁,有的时候这种方式会增加持有锁的时间,降低系统的性能,比如在web开发中是不允许在接收请求的方法声明上使用synchronized。synchronized既可以修饰普通的实例方法,也可以修饰静态方法。如果修饰实例方法,锁就会和调用该方法的实例对象相关联;如果修饰静态方法,锁就会和调用该静态方法的类对应的Class对象关联。

  另一种同步方式是使用synchronized来定义一个单独的代码块,看一个实例:

  java程序员修炼之路线程篇四:同步

  这种方式下锁会和参数对象相关联。很多时候一个程序中会定义很多这种同步块,这些同步块必须获取同一个锁,否则就不存在同步了。比如我们定义了一个同步块是synchronized(mynumber),而另外一个同步块是synchronized(yournumber),这是两个不同的锁,也就不存在同步了。同步块在实际开发中应用比较广泛,掌握它的应用是十分必要的。

  今天跟大家聊了一下同步在线程编程中的应用,同步的应用也标志着我的线程篇开始进入"深水区",同时同步的应用也会导致一些新的问题,比如"死锁",我将在下一篇文章中跟大家探讨关于"死锁"的问题,请大家持续关注。

    转藏 分享 献花(0

    0条评论

    发表

    请遵守用户 评论公约

    类似文章 更多