同步.概念
java线程的同步概念是个很有意义的玩意。synchronize从英译过来是"是同时发生"。
但其真正的含义确实截然相反的。线程同步的真实意思,其实是“排队”:几个线程之间要排队,一个一个对共享资源进行操作,而不是同时进行操作。
同步.目的
而最让人无语的是,线程同步的目的就是让各个线程去排队使用资源,而不是让线程同时去使用资源。
同步.时机
情况1.线程何时才需要同步,这里就涉及到"共享"的概念。但多个线程需要访问同一份资源,也就是共享资源的时候就需要同步操作。这也好理解,因为资源就那么多,如果多个线程同时访问,就很容易造成死锁问题。
情况2.共享资源是变量,并且至少有一个线程去改变共享资源。这时候也需要同步,这也很好理解,防止数据脏读造成巨大影响
同步.如何同步
使用同步锁。
同步.在何处添加同步锁
a.把锁添加到共享文件中
从意义上解释,如何能让访问者按照先后顺序去访问资源。那最简单的就是给这个资源添加一个锁的概念。这把锁只有一把钥匙,只有拥有这把钥匙的线程才能访问共享资源。所以,这就使线程有先后顺序。
b.把锁添加到访问共享资源的代码段(线程中)
实际操作中,对于那么大型数据库,文档文件,他们本身就具备比较完善的锁。但对于我们实际编程的时候,需要访问的共享资源往往都是比较小的,所以,在这么小的资源上添加锁,会很不方便。所以会把锁添加到代码中
同步锁.概念
java中,任何一个Object Reference都可以作为同步锁。什么是Object Reference,我们可以把Object Reference理解为对象在内存分配系统中的内存地址。因此,要保证同步代码段之间使用的是同一个同步锁,我们就要保证这些同步代码段的synchronized关键字使用的是同一个内存地址。
同步锁.代码上添加什么样的锁
可以肯定的是,访问同一份共享资源的不同代码上添加的锁肯定是同一个锁。(个人理解,因为线程代码都是同一个锁,所以当有一个线程代码去访问共享资源的时候就需要资源的钥匙去打开这把锁。换句话说,能打开其他线程代码的钥匙正在被使用,所以其他线程只能等待前一个线程完毕并释放"钥匙"),所以这个锁也是一个共享对象。
同步锁.如何给代码添加锁
Java语言里面用synchronized关键字给代码段加锁。
synchronized(同步锁) {
// 访问共享资源,需要同步的代码段
}
这里需要重点说明,synchronized关键字使用的一定是同一个内存地址。一定要确保这个内存地址不会变(换句话说,是这个同步对象不会在函数体重声明定义而会反反复复的新建)。
同步颗粒.概念
同步代码段的范围,同步颗粒越小越好,也就是同步代码段的范围越来越来。
同步颗粒.如何减小同步颗粒
方法a.对于访问不同的共享资源,没必要去竞争同一个同步锁。例子
public static final Object lock1 = new Object();
… f1() {
synchronized(lock1){ // lock1 是公用同步锁
// 代码段 A
// 访问共享资源 resource1
// 需要同步
}
}
… f2() {
synchronized(lock1){ // lock1 是公用同步锁
// 代码段 B
// 访问共享资源 resource1
// 需要同步
}
}
… f3() {
synchronized(lock1){ // lock1 是公用同步锁
// 代码段 C
// 访问共享资源 resource2
// 需要同步
}
}
… f4() {
synchronized(lock1){ // lock1 是公用同步锁
// 代码段 D
// 访问共享资源 resource2
// 需要同步
}
}
这个例子就很形象的说明同步锁的不正确使用,f3()和f4()访问的资源和f1()f2()根本就不一样,这时候就没必要再去竞争同一个锁,可以新建一个锁。
参考:https://blog.csdn.net/qq_39285447/article/details/78995092