从分布式锁角度理解Java的synchronized关键字

分布式锁

分布式锁就以zookeeper为例,zookeeper是一个分布式系统的协调器,我们将其理解为一个文件系统,可以在zookeeper服务器中创建或删除文件夹或文件.设D为一个数据系统,不具备事务能力,在并发状态下可能出现对单个数据同时读写.客户端A,B是数据系统D提供的客户端,能够对其读写.

几个关键角色已经登场,D是一个不提供事务行为的数据系统,其存放的数据可被读写,在单客户端条件下可以保证数据的可靠,但是在两个客户端可能并发请求时就变得不可靠,A写的数据可能被B覆盖,B读的数据可能是A没有写完的数据.在不修改D源码为其提供原子性操作的前提下,我们可以考虑分布式锁.

客户端的原始API

void write(){
    // 写数据
}
void read(){
    // 读数据
}

如何做呢,核心就是以zookeeper为媒介.

修改客户端API,如果读或者写,我们首先要在zookeeper上创建一个文件夹,如果创建成功,我们就执行读写操作,如果不成功(代表已经有人创建了)我们就一直尝试创建,直到创建成功.当创建成功时,对D系统的数据进行读写操作,完成后删除zookeeper上创建的文件夹并退出读写方法.

void write(){
 while(在zookeeper上创建文件夹) {
     写操作;
     删除zookeeper的刚创建的文件夹;
     return;
 }
}

这样就完成了一个分布式并发行为的同步.假设A已经创建了文件夹,B就没办法进行后续操作,会一直尝试创建文件夹,A执行完操作之后删除文件夹,B才有机会进行在D系统上的操作.这个例子中产生了一个临界资源:D系统的数据,和一个竞态条件:A和B并发读写.(实际上zookeeper中是可以为监听者发送文件情况的,比如我创建文件夹没有成功,可以监听该文件夹,当文件夹变化时会通知你,这时候你就可以再尝试创建文件夹了(很像wait和notify),但是为了不把重心放在zookeeper上就没有改成监听模式)

Java中Synchronized关键字

那我们再回到Java中的synchronized关键字上来,如果你还没理解上面的行为和synchronized的关系你可以继续往后看.

synchronized究竟锁住的是什么呢,锁住的是一块内存,我们在内存中的某个位置设置一个值为0,当该值为0时,一个线程为了修改临界资源将其设置为1,然后读写操作,读写结束将其设置为0,其他线程可以再次将其改为1,进行读写,结束后再将其置为0......这块内存存储在每个对象的对象头中,我们称其为锁标志位(实际上所标志位不是简单的0和1,锁标志位分为四种状态:无锁,偏向锁,轻量级锁,和重量级锁,并发中还涉及锁升级等,但本文不做细究,有兴趣的读者可以查阅相关资料).

当进入synchronized代码块或者方法的时候,你会像上面说的分布式锁那样"创建一个文件夹",其他线程无法"创建文件夹"就会一直去尝试,当代码块或方法结束的时候会"删除文件夹",其他线程可以去抢夺创建文件夹的机会.synchronized可以看做一道门,锁住的对象可以看做是门票.千万不要认为synchronized锁住的是临界资源,synchronized是以某个对象的锁标志作为入场券去约束竞态线程之间行为:我只有一张门票,我只给一个人.

看一下synchronized的用法,多个线程之间的竞态行为一定要是用相同的门票去约束.

// 这锁住的是
class Foo{
    // 这锁住的是类对象
    static synchronized void bar();
    // 这锁住的是this,即实例对象
    synchronized void bar();
    // 等价于static synchronized
    void bar(){
        synchronized(Foo.class){};
    }
    // 等价于synchronized实例方法
    void bar(){
        synchronized(this){}
    }
}

对于静态方法需要注意一点(假如你想观察偏向锁的变化),实例方法可以直接观察实例对象的对象头上的锁标志位,但是静态方法需要观察Foo.class对象的锁标志位,如果观察实例对象的锁标志位会竹篮打水哟.

原文地址:https://www.cnblogs.com/krcys/p/9379836.html

时间: 2024-08-11 07:48:36

从分布式锁角度理解Java的synchronized关键字的相关文章

Java对象锁和类锁全面解析(多线程synchronized关键字)

最近工作有用到一些多线程的东西,之前吧,有用到synchronized同步块,不过是别人怎么用就跟着用,并没有搞清楚锁的概念.最近也是遇到一些问题,不搞清楚锁的概念,很容易碰壁,甚至有些时候自己连用没用对都不知道. 今天把一些疑惑都解开了,写篇文章分享给大家,文章还算比较全面.当然可能有小宝鸽理解得不够深入透彻的地方,如果说得不正确还望指出. 看之前有必要跟某些猿友说一下,如果看一遍没有看明白呢,也没关系,当是了解一下,等真正使用到了,再回头看. 本文主要是将synchronized关键字用法作

Java基础-synchronized关键字的用法(转载)

原文地址:http://blog.csdn.net/cq361106306/article/details/38736551 synchronized--同步 顾名思义是用于同步互斥的作用的. 这里精简的记一下它的使用方法以及意义: 当synchronized修饰?this或者非静态方法或者是一个实例的时候,所同步的锁是加在this或者实例对象引用上面的.比如a,b同为Main类的实例化对象,a调用被同步的方法,和b调用被同步的方法,没有形成互斥.但是不同线程的a对象调用被同步的方法就被互斥了.

Java中synchronized关键字理解

好记性不如烂笔头~~ 并发编程中synchronized关键字的地位很重要,很多人都称它为重量级锁.利用synchronized实现同步的基础:Java中每一个对象都可以作为锁.具体表现为以下三种形式. (1)对于普通同步方法,锁是当前实例对象. (2)对于静态同步方法,锁是当前类的Class对象. (3)对于同步方法块,锁是synchronized括号里配置的对象. 一.普通同步方法 使用synchronized关键字修饰一个普通方法,锁住的是当前实例的对象.当synchronized锁住该对

Java关于Synchronized关键字在不同位置使用的理解

Java中的Synchronized关键字 可以用来修饰同步方法: 像这样synchronized void f() {/*body*/} 也可以修饰同步语句块: 像这样synchronized(object){/*body*/}. 其中修饰同步方法还可以分为修饰static方法和实例方法. 其中修饰同步语句块还可以分为修饰instance变量,Object Reference对象引用,class 字面常量. 当synchronized作用在方法上时,锁住的便是对象实例(this): 所以syn

java中synchronized关键字的用法

在java编程中,经常需要用到同步,而用得最多的也许是synchronized关键字了,下面看看这个关键字的用法. 因为synchronized关键字涉及到锁的概念,所以先来了解一些相关的锁知识. java的内置锁:每个java对象都可以用做一个实现同步的锁,这些锁成为内置锁.线程进入同步代码块或方法的时候会自动获得该锁,在退出同步代码块或方法时会释放该锁.获得内置锁的唯一途径就是进入这个锁的保护的同步代码块或方法. java内置锁是一个互斥锁,这就是意味着最多只有一个线程能够获得该锁,当线程A

Java多线程synchronized关键字

synchronized关键字代表着同步的意思,在Java中被synchronized修饰的有三种情况 1.同步代码块 //锁为objsynchronized(obj){ while(true){ if(product > 0){ System.out.println(Thread.currentThread().getName()+"消费:"+product--); } } } 2.同步函数 //锁为thispublic synchronized void consume()

从设计模式角度理解Java IO基本概念

1.基本概念 1.1.InputStream 最基本的字节输入流,抽象类,定义了读取原始字节的所有基本方法1.1.1.public abstract int read() throws IOException 读取一个字节的方法,最基础的方法1.1.2.public int read(byte b[], int off, int len) 读取指定长度的字节到字节数组,基于方法1.1.11.1.3.public int read(byte b[]) throws IOException 读取一个

尝试在C++里实现 Java 的 synchronized 关键字

话说Java里有个很强大的关键字叫synchronized,可以方便的实现线程同步.今天异想天开,尝试在C++里模拟一个类似的. 最近在学习C++的STL,看见智能指针这章节时,无不感叹利用语言的丰富特征,来各种实现各种巧妙的构思.最经典的莫过于使用栈对象构造/析构函数,来维护局部资源的初始化和释放.照着这个巧妙的方法,依样画葫芦自己也来写一个,来实现局部代码线程同步. Java里的synchronized有两种形式,一种是基于函数的,另种则是语块的.前者受C++的语法所限,估计是没法实现了,所

Java中synchronized关键字实现同步(二)

我们知道synchronized有两种:同步方法(synchronized method)和同步语句块(synchronized block).那么这两种有什么区别以及优缺点呢? SynchronizedMethod: 优点:代码简单清晰:易于维护 缺点:同步粒度过大,不利于并发:不够灵活,默认用本对象或者本类锁同步 Synchronizedblock  : 优点:灵活,可以使用任意对象锁:同步粒度小,并发度更高 缺点:代码更复杂,不易于维护 对比: Synchronized method: 默