首页 > 其他分享 >synchronized 经典问题之“线程八锁”

synchronized 经典问题之“线程八锁”

时间:2023-12-16 20:32:11浏览次数:29  
标签:八锁 synchronized void Number 线程 n1 new public

synchronize简介

一、单个对象的同步。每个方法可以同步到不同的对象,对象之间是相互独立的。

private Object synObject1 = new Object();
    private Object synObject2 = new Object();
    }
    public void f1() {
        synchronized (synObject1) {
            //TODO
        }
    }

    public void f2() {
        synchronized (synObject2) {
            //TODO
        }
    }

f1与f2分别同步到不同的对象上,只要获得相应同步对象的对象锁,线程就可以运行。

二、同步到当前类实例对象上。当某一个方法同步到当前的类实例对象上时,线程只有获得当前类实例的对象锁才可以继续运行。同步到当前类实例对象上有两种方法:

1、同步对象设为this。

public void f3() {
        synchronized (this) {
            //TODO
        }
    }

2、在方法上使用synchronize关键字。

public synchronized void f4() {
        // TODO
    }

三、同步到当前类实例上。当使用一个静态对象作为同步对象时,线程只有获得当前类实例时,才可以继续运行,也就是所谓的类锁。也可以直接获取当前类实例来作为同步对象,有两种方法:

1、使用xxx.class

public class Test {
    public void f6() {
        synchronized (Test.class) {
            // TODO
        }
    }
}

2、使用Class.forName(XXXX);

public class Test {
public void f7() throws ClassNotFoundException {
        synchronized (Class.forName("com.example.Test")) {
            // TODO
        }
    }
}

3.静态方法

public class Test {
public synchronized void f7() {
        
    }
}

所谓的“线程八锁”

其实就是考察 synchronized 锁住的是哪个对象

情况1:12 或 21

@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();
}

情况2:1s后12,或 2 1s后 1

@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();
}

以上两个测试,可以看出synchronized修饰的方法,同一时刻,只能有一个线程进入

情况3:3 1s 12 或 23 1s 1 或 32 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();
}

c方法没有被synchronized修饰,所以c方法肯定会被执行,a,b方法被synchronized修饰,同一时刻只能执行其中一个。

情况4:2 1s 后 1

@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();
}

synchronized加在方法上锁的是当前对象,n1与n2不是同一个对象,此时synchronized是不生效的

情况5:2 1s 后 1

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();
}

synchronized加在静态方法上锁的是Number.class,synchronized加在方法上锁的是当前对象。两者锁的不是同一个东西。相当于synchronized失效了,所以最后的输出结果为2 1s 后 1

情况6:1s 后12, 或 2 1s后 1

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();
}

synchronized加在静态方法上锁的是Number.class,同一时间只能有一个线程调用a方法或b方法

情况7:2 1s 后 1

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();
}

synchronized加在静态方法上锁的是Number.class,synchronized加在方法上锁的是当前对象。两者锁的不是同一个东西。相当于synchronized失效了,所以最后的输出结果为2 1s 后 1

情况8:1s 后12, 或 2 1s后 1

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();
}

synchronized加在静态方法上锁的是Number.class,同一时间只能有一个线程调用a方法或b方法,所以输出结果为:1s 后12 或 2 1s后 1

标签:八锁,synchronized,void,Number,线程,n1,new,public
From: https://blog.51cto.com/AmbitionGarden/8854040

相关文章

  • Java 中变量的线程安全问题
    Java中的变量主要分为静态变量、普通成员变量、局部变量等,这些变量在单线程环境下是不会有线程安全问题的,但是多线程环境下实际情况又是什么样子的呢?1、成员变量和静态变量如果成员变量和静态变量不存在多个线程共享操作,那么不会有线程安全问题如果成员变量和静态变量被......
  • 线程组内几个配置原件的说明
    一、http信息头管理器1、设置请求接口提交参数的格式,一般接口的开发文档文档会有相应的说明,类型会有application,x-www-form-urlencoded等,application是提交的参数以json的格式发送,x-www-form-urlencoded是以浏览器默认表达的方式提交,根据接口说明文档设置即可二、http请求默认......
  • SpringBoot使用Async注解实现异步线程
    1、启动类增加@EnableAsync注解2、yml增加配置spring:task:execution:pool:max-size:8core-size:8keep-alive:60queue-capacity:1000thread-name-prefix:Asnyc-task-calc-3、编写配置类AsyncTaskConfigimp......
  • Python多线程编程:竞争问题的解析与应对策略
    本文将深入探讨Python多线程编程中可能出现的竞争问题、问题根源以及解决策略,旨在帮助读者更好地理解、应对并发编程中的挑战。多线程竞争问题的复杂性源自于对共享资源的并发访问和操作。在不同线程间的交叉执行中,共享资源可能因无序访问而导致数据不一致、死锁或饥饿等问题。解决......
  • Java核心知识体系8:Java如何保证线程安全性
    Java核心知识体系1:泛型机制详解Java核心知识体系2:注解机制详解Java核心知识体系3:异常机制详解Java核心知识体系4:AOP原理和切面应用Java核心知识体系5:反射机制详解Java核心知识体系6:集合框架详解Java核心知识体系7:线程不安全分析1Java内存模型(JMM)如何解决并发问题维度1:使......
  • Java-创建线程池的参数及工作原理
    Java-创建线程池的参数及工作原理常见的参数corePoolSize(核心线程数):线程池中保持的最小线程数,即使它们是空闲的。maximumPoolSize(最大线程数):线程池中允许的最大线程数。keepAliveTime(线程空闲时间):当线程池中的线程数超过核心线程数时,多余的空闲线程在被终止之前等待新......
  • Java-创建线程池的参数及工作原理
    Java-创建线程池的参数及工作原理常见的参数corePoolSize(核心线程数):线程池中保持的最小线程数,即使它们是空闲的。maximumPoolSize(最大线程数):线程池中允许的最大线程数。keepAliveTime(线程空闲时间):当线程池中的线程数超过核心线程数时,多余的空闲线程在被终止之前等待新......
  • Java-创建线程池的参数及工作原理
    Java-创建线程池的参数及工作原理常见的参数corePoolSize(核心线程数):线程池中保持的最小线程数,即使它们是空闲的。maximumPoolSize(最大线程数):线程池中允许的最大线程数。keepAliveTime(线程空闲时间):当线程池中的线程数超过核心线程数时,多余的空闲线程在被终止之前等待新......
  • Synchronized 和 Lock 的区别和使用场景
    Synchronized和Lock的概念Synchronized 是Java并发编程中很重要的关键字,另外一个很重要的是 volatile。Syncronized的目的是一次只允许一个线程进入由他修饰的代码段,从而允许他们进行自我保护。Synchronized很像生活中的锁例子,进入由Synchronized保护的代码区首先需要获......
  • 两个线程共享一个套接字,其中一个线程使用sendmsg函数不断发送消息到该套接字,另一个线
    以下是使用C语言写的一段代码,实现两个线程共享一个套接字,其中一个线程使用sendmsg函数不断发送消息到该套接字,另一个线程使用recvmsg函数不断接收该套接字的消息,并打印出来的功能点击查看代码#include<stdio.h>#include<stdlib.h>#include<string.h>#include<unistd.......