目录
对象锁
定义
形如:
synchronized void method(){ // 在普通成员方法上加锁 // 临界区 } void method(){ synchronized(this){ // 锁住当前对象 // 临界区 } }
两种方式的临界区,对于同一个对象是等效的
对象锁例子
在普通方法上加锁(相同对象调用相同方法)
package com.juc.ppy.synchronize;
import lombok.extern.slf4j.Slf4j;
@Slf4j(topic = "c.MethodSynchronized")
public class MethodSynchronized {
public MethodSynchronized(){ // 每次创建新对象,都打印出该对象的 hash 码
log.debug("创建了 MethodSynchronized 新对象 {}", this.hashCode());
}
public synchronized void getTime1(){ // 在普通成员方法上加锁
try{
log.debug("在普通方法加锁");
Thread.sleep(2000); // sleep() 不会释放锁,用来证明锁起作用了
}catch (Exception e){
e.printStackTrace();
}
log.debug("结束");
}
}
class Test3{
public static void main(String[] args) throws InterruptedException {
MethodSynchronized ms = new MethodSynchronized();
Thread t1 = new Thread(() -> { // 线程 1 调用 getTime1()
ms.getTime1();
}, "t1");
Thread t2 = new Thread(() -> { // 线程 2 调用 getTime1()
ms.getTime1();
}, "t2");
t1.start();
t2.start();
t1.join();
t2.join();
}
}
① 第 2 秒创建出对象 ms
② 紧接着线程 t1 获取到锁,开始执行;第 4 秒结束,释放锁
③ 线程 t2 获取到锁,开始执行;第 6 秒结束
综上:t1、t2 共用 ms 这一把锁
对当前对象加锁(相同对象调用相同方法)
@Slf4j(topic = "c.MethodSynchronized")
public class MethodSynchronized {
public MethodSynchronized(){ // 每次创建新对象,都打印出该对象的 hash 码
log.debug("创建了 MethodSynchronized 新对象 {}", this.hashCode());
}
public void getTime2(){
synchronized (this){ // 在当前对象上加锁
try{
log.debug("synchronized (this)");
Thread.sleep(2000);
}catch (Exception e){
e.printStackTrace();
}
log.debug("结束");
}
}
}
class Test4{
public static void main(String[] args) throws InterruptedException {
MethodSynchronized ms = new MethodSynchronized();
Thread t1 = new Thread(() -> {
ms.getTime2();
}, "t1");
Thread t2 = new Thread(() -> {
ms.getTime2();
}, "t2");
t1.start();
t2.start();
t1.join();
t2.join();
}
}
情况与上面一样,说明这两种加锁方式是等效的
不同对象调用相同方法 && 相同对象调用不同方法
@Slf4j(topic = "c.MethodSynchronized")
public class MethodSynchronized {
public MethodSynchronized(){ // 每次创建新对象,都打印出该对象的 hash 码
log.debug("创建了 MethodSynchronized 新对象 {}", this.hashCode());
}
public void method(){
synchronized (this){ // 在当前对象上加锁
try{
log.debug("先芜湖~");
Thread.sleep(2000);
}catch (Exception e){
e.printStackTrace();
}
log.debug("再起飞!");
}
}
}
class Test6{
public static void main(String[] args) throws InterruptedException {
MethodSynchronized ms1 = new MethodSynchronized();
MethodSynchronized ms2 = new MethodSynchronized();
Thread t1 = new Thread(() -> {
ms1.method();
}, "t1");
Thread t2 = new Thread(() -> {
ms2.method();
}, "t2");
t1.start();
t2.start();
t1.join();
t2.join();
}
}
① 创建了 ms1、ms2 两个对象
② 第 59 秒 t1、t2 几乎同时执行
③ 第 1 秒 t1、t3 几乎同时结束
综上:锁没起作用
@Slf4j(topic = "c.MethodSynchronized")
public class MethodSynchronized {
public MethodSynchronized(){ // 每次创建新对象,都打印出该对象的 hash 码
log.debug("创建了 MethodSynchronized 新对象 {}", this.hashCode());
}
public synchronized void getTime1(){ // 在普通成员方法上加锁
try{
log.debug("在普通方法加锁");
Thread.sleep(2000); // sleep() 不会释放锁,用来证明锁起作用了
}catch (Exception e){
e.printStackTrace();
}
log.debug("结束");
}
public void getTime2(){
synchronized (this){ // 在当前对象上加锁
try{
log.debug("synchronized (this)");
Thread.sleep(2000);
}catch (Exception e){
e.printStackTrace();
}
log.debug("结束");
}
}
}
class Test7{
public static void main(String[] args) throws InterruptedException {
MethodSynchronized ms = new MethodSynchronized();
Thread t1 = new Thread(() -> { // t1 调用方法 1
ms.getTime1();
}, "t1");
Thread t2 = new Thread(() -> { // t2 调用方法 2
ms.getTime2();
}, "t2");
t1.start();
t2.start();
t1.join();
t2.join();
}
}
总结:同一个对象属于同一把锁
① 不同对象调用相同方法,锁不起作用;是因为 ms1、ms2 相当于两把锁,分别被 t1、t2 获取;锁不同,临界区就不一样,它们相互之间是不影响的,各执行各的
② 相同对象调用不同方法,锁起作用;对象相同,锁就相同,临界区就相同
类锁
定义
形如:
static synchronized void method(){ // 在静态成员方法上加锁 // 临界区 } void method(){ synchronized(类名.class){ // 对当前类加锁 // 临界区 } }
两种方式的临界区,对于同一个类是等效的
类锁例子
在静态方法上加锁(不同对象调用相同方法)
@Slf4j(topic = "c.ClassSynchronized")
public class ClassSynchronized {
public ClassSynchronized(){ // 每次创建新对象,都打印出该对象的 hash 码
log.debug("创建了 ClassSynchronized 新对象 {}", this.hashCode());
}
private static synchronized void getTime0(){ // 在静态成员方法上加锁
try{
log.debug("在静态方法加锁");
Thread.sleep(2000); // sleep() 不会释放锁,用来证明锁起作用了
}catch (Exception e){
e.printStackTrace();
}
log.debug("结束");
}
public void getTime(){ // 最终调用的方法;用来证明:即使是不同对象,锁也是一样的
getTime0();
}
}
class Test0{
public static void main(String[] args) throws InterruptedException {
ClassSynchronized cs1 = new ClassSynchronized(); // 创建对象 1
ClassSynchronized cs2 = new ClassSynchronized(); // 创建对象 2
Thread t1 = new Thread(() -> {
cs1.getTime(); // 线程 1 中调用对象 1 的普通方法
}, "t1");
Thread t2 = new Thread(() -> {
cs2.getTime();
}, "t2"); // 线程 2 中调用对象 2 的普通方法
t1.start();
t2.start();
t1.join();
t2.join();
}
}
① 第 36 秒创建出对象 cs1、cs2
② 紧接着线程 t1 获取到锁,开始执行;第 38 秒结束,释放锁
③ 线程 t2 获取到锁,开始执行;第 40 秒结束
综上:虽然 cs1、cs2 是两个不同对象,但是属于同一个类,同一个临界区,t1、t2 它们共用一把类锁
对当前类加锁(不同对象调用相同方法)
@Slf4j(topic = "c.ClassSynchronized")
public class ClassSynchronized {
public void getTime1(){
synchronized (ClassSynchronized.class){ // 直接锁住当前类
try{
log.debug("synchronized (ClassSynchronized.class)");
Thread.sleep(2000);
}catch (Exception e){
e.printStackTrace();
}
log.debug("结束");
}
}
}
class Test1{
public static void main(String[] args) throws InterruptedException {
ClassSynchronized cs1 = new ClassSynchronized();
ClassSynchronized cs2 = new ClassSynchronized();
Thread t1 = new Thread(() -> {
cs1.getTime1();
}, "t1");
Thread t2 = new Thread(() -> {
cs2.getTime1();
}, "t2");
t1.start();
t2.start();
t1.join();
t2.join();
}
}
情况与上面一样,说明这两种加锁方式是等效的
不同对象调用不同方法
@Slf4j(topic = "c.ClassSynchronized")
public class ClassSynchronized {
public ClassSynchronized(){ // 每次创建新对象,都打印出该对象的 hash 码
log.debug("创建了 ClassSynchronized 新对象 {}", this.hashCode());
}
public void method1(){ // 方法 1 芜湖
synchronized (ClassSynchronized.class){ // 直接锁住当前类
try{
log.debug("芜湖~");
Thread.sleep(2000);
}catch (Exception e){
e.printStackTrace();
}
log.debug("芜湖~");
}
}
public void method2(){ // 方法 2 起飞
synchronized (ClassSynchronized.class){ // 直接锁住当前类
try{
log.debug("起飞!");
Thread.sleep(2000);
}catch (Exception e){
e.printStackTrace();
}
log.debug("起飞!");
}
}
}
class Test2{
public static void main(String[] args) throws InterruptedException {
ClassSynchronized cs1 = new ClassSynchronized();
ClassSynchronized cs2 = new ClassSynchronized();
Thread t1 = new Thread(() -> {
cs1.method1(); // cs1 调用 芜湖
}, "t1");
Thread t2 = new Thread(() -> {
cs2.method2(); // cs2 调用 起飞
}, "t2");
t1.start();
t2.start();
t1.join();
t2.join();
}
}
不同对象,调用不同方法,锁依旧起作用;足以说明对于同一个类都属于同一把锁
线程八锁
第一锁
@Slf4j(topic = "c.Number")
class Number{
public synchronized void a() {
log.debug("1");
}
public synchronized void b() {
log.debug("2");
}
}
public static void main(String[] args) {
Number n1 = new Number();
new Thread(()->{ n1.a(); }).start();
new Thread(()->{ n1.b(); }).start();
}
结果:12 或 21
第二锁
@Slf4j(topic = "c.Number")
class Number{
public synchronized void a() {
sleep(1);
log.debug("1");
}
public synchronized void b() {
log.debug("2");
}
}
public static void main(String[] args) {
Number n1 = new Number();
new Thread(()->{ n1.a(); }).start();
new Thread(()->{ n1.b(); }).start();
}
结果:1s 后 12 或 2 过 1s 后 1
第三锁(难点)
class Number{
public synchronized void a() {
sleep(1);
log.debug("1");
}
public synchronized void b() {
log.debug("2");
}
public void c() {
log.debug("3");
}
}
public static void main(String[] args) {
Number n1 = new Number();
new Thread(()->{ n1.a(); }).start();
new Thread(()->{ n1.b(); }).start();
new Thread(()->{ n1.c(); }).start();
}
结果:3 过 1s 后 12 或 32 过 1s 后 1 或 23 过 1s 后 1
说明:方法 c 没有加锁;sleep 会释放时间片,就算第二个线程获得了时间片,由于没有锁进入阻塞;所以不可能出现 "13" 这种结果
第四锁
@Slf4j(topic = "c.Number")
class Number{
public synchronized void a() {
sleep(1);
log.debug("1");
}
public synchronized void b() {
log.debug("2");
}
}
public static void main(String[] args) {
Number n1 = new Number();
Number n2 = new Number();
new Thread(()->{ n1.a(); }).start();
new Thread(()->{ n2.b(); }).start();
}
结果:2 1s 后 1
第五锁(难点)
@Slf4j(topic = "c.Number")
class Number{
public static synchronized void a() {
sleep(1);
log.debug("1");
}
public synchronized void b() {
log.debug("2");
}
}
public static void main(String[] args) {
Number n1 = new Number();
new Thread(()->{ n1.a(); }).start();
new Thread(()->{ n1.b(); }).start();
}
结果:2 1s 后 1
说明:a 加的是类锁,b 加的是对象锁;相当于不同锁,互不影响
第六锁
@Slf4j(topic = "c.Number")
class Number{
public static synchronized void a() {
sleep(1);
log.debug("1");
}
public static synchronized void b() {
log.debug("2");
}
}
public static void main(String[] args) {
Number n1 = new Number();
new Thread(()->{ n1.a(); }).start();
new Thread(()->{ n1.b(); }).start();
}
结果:2 1s 后 1 或 1s 后 12
第七锁
@Slf4j(topic = "c.Number")
class Number{
public static synchronized void a() {
sleep(1);
log.debug("1");
}
public synchronized void b() {
log.debug("2");
}
}
public static void main(String[] args) {
Number n1 = new Number();
Number n2 = new Number();
new Thread(()->{ n1.a(); }).start();
new Thread(()->{ n2.b(); }).start();
}
结果:2 1s 后 1
第八锁
@Slf4j(topic = "c.Number")
class Number{
public static synchronized void a() {
sleep(1);
log.debug("1");
}
public static synchronized void b() {
log.debug("2");
}
}
public static void main(String[] args) {
Number n1 = new Number();
Number n2 = new Number();
new Thread(()->{ n1.a(); }).start();
new Thread(()->{ n2.b(); }).start();
}
结果:2 1s 后 1 或 1s 后 12