synchronized的多种用法

  |   1 评论   |   602 浏览

用法一 synchronized作用在方法

synchronized作用在方法上有两种情况

1.作用在静态方法上

 1public static void main(String[] args) {
 2    new Thread(() -> {
 3        try {
 4            a();
 5        } catch (InterruptedException e) {
 6            e.printStackTrace();
 7        }
 8    }, "t1").start();
 9    new Thread(() -> {
10        try {
11            a();
12        } catch (InterruptedException e) {
13            e.printStackTrace();
14        }
15    }, "t2").start();
16}
17public static synchronized void a() throws InterruptedException {
18    System.out.println(Thread.currentThread().getName() + "进入了方法a");
19    for (; ; ) {
20        Thread.sleep(2000);
21    }
22}

执行结果

image.png

可以得出结论当synchronized作用在静态方法上时持有锁的是当前类, t1线程进入后进入死循环, t2将会一直等待, 发生死锁

2.作用在非静态方法上

 1public class SynchronizedTest {
 2    public static void main(String[] args) {
 3        new Thread(() -> {
 4            try {
 5                new SynchronizedTest().a();
 6            } catch (InterruptedException e) {
 7                e.printStackTrace();
 8            }
 9        }, "t1").start();
10        new Thread(() -> {
11            try {
12                new SynchronizedTest().a();
13            } catch (InterruptedException e) {
14                e.printStackTrace();
15            }
16        }, "t2").start();
17    }
18
19    public synchronized void a() throws InterruptedException {
20        System.out.println(Thread.currentThread().getName() + "进入了方法a");
21        for (; ; ) {
22            Thread.sleep(2000);
23        }
24    }
25}

执行结果
image.png

这时候发现t1和t2线程都进入了方法a,所以这时候持锁的是当前对象,两个线程都是new新对象调用了a(),所以他们各玩各的互不影响

synchronized修饰代码块

一般修饰代码块也有两种用法

1.synchronized代码块传入this

 1public static void main(String[] args) {
 2    new Thread(() -> {
 3        try {
 4            new SynchronizedTest().a();
 5        } catch (InterruptedException e) {
 6            e.printStackTrace();
 7        }
 8    }, "t1").start();
 9    new Thread(() -> {
10        try {
11            new SynchronizedTest().a();
12        } catch (InterruptedException e) {
13            e.printStackTrace();
14        }
15    }, "t2").start();
16}
17public void a() throws InterruptedException {
18    synchronized (this) {
19        System.out.println(Thread.currentThread().getName() + "进入了方法a");
20        for (; ; ) {
21            Thread.sleep(2000);
22        }
23    }
24}

image.png

两个线程都进入了方法, 这种情况和synchronized修饰非静态方法时是一样的,每次执行到代码块的对象并非同一个

2.synchronized代码块传入class

 1public class SynchronizedTest {
 2    public static void main(String[] args) {
 3        new Thread(() -> {
 4            try {
 5                new SynchronizedTest().a();
 6            } catch (InterruptedException e) {
 7                e.printStackTrace();
 8            }
 9        }, "t1").start();
10        new Thread(() -> {
11            try {
12                new SynchronizedTest().a();
13            } catch (InterruptedException e) {
14                e.printStackTrace();
15            }
16        }, "t2").start();
17    }
18
19    public void a() throws InterruptedException {
20        synchronized (SynchronizedTest.class) {
21            System.out.println(Thread.currentThread().getName() + "进入了方法a");
22            for (; ; ) {
23                Thread.sleep(2000);
24            }
25        }
26    }
27}

image.png

这种情况锁的是当前类, 所以t1持锁的时候t2是进不来的

总结:
1.当synchronized作用在静态方法时, 所有线程都共用一把锁
2.当synchronized作用在非静态方法时, 相同实例共用一把锁
3.当synchronized代码块传入类时,所有线程都共用一把锁
4.当synchronized代码块传入this时, 相同实例共用一把锁


作者:wenbo

评论

发表评论


取消