0
点赞
收藏
分享

微信扫一扫

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

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

举报

相关推荐

0 条评论