synchronized修饰静态方法和普通方法的区别 和 应用

synchronized 可以锁类方法(静态方法) 或者 普通方法

修饰普通方法

1.先看单个对象代码

package com.thread;

public class SynchronizedTest {

    synchronized public void function1() throws InterruptedException {
        String name = Thread.currentThread().getName();
        for (int i = 0; i < 5; i++){
            System.out.println("function1 " + name);
            Thread.sleep(1000);
        }
    }

    synchronized public void function2() throws InterruptedException {
        String name = Thread.currentThread().getName();
        for (int i = 0; i < 5; i++){
            System.out.println("function2 " + name);
            Thread.sleep(1000);
        }
    }

    public static void main(String[] args) throws InterruptedException {
        SynchronizedTest s1 = new SynchronizedTest();

        new Thread(() -> {
            System.out.println("Thread1 is start");
            try {
                s1.function1();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("Thread1 is end");

        }).start();

        new Thread(() -> {
            System.out.println("Thread2 is start");
            try {
                s1.function2();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("Thread2 is end");

        }).start();
    }
}

z

首先看,我们创建的对象s1,在不同线程分别执行不同的两个普通方法(实例方法),因为synchronized 锁住的是对象(对象锁),所以按照执行顺序是function1 再试function2
纵然function2想去执行方法,但是,因为对象锁锁住的是s1对象,所以必须等到function1执行完毕function2中才能获得锁执行方法

2.再看多个对象代码

为了验证这个,我们再去建立一个对象s2,开启线程执行function2.
package com.thread;

public class SynchronizedTest {

    synchronized public void function1() throws InterruptedException {
        String name = Thread.currentThread().getName();
        for (int i = 0; i < 5; i++){
            System.out.println("function1 " + name);
            Thread.sleep(1000);
        }
    }

    synchronized public void function2() throws InterruptedException {
        String name = Thread.currentThread().getName();
        for (int i = 0; i < 5; i++){
            System.out.println("function2 " + name);
            Thread.sleep(1000);
        }
    }

    public static void main(String[] args) throws InterruptedException {
        SynchronizedTest s1 = new SynchronizedTest();
        SynchronizedTest s2 = new SynchronizedTest();
        new Thread(() -> {
            System.out.println("Thread1 is start");
            try {
                s1.function1();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("Thread1 is end");

        }).start();

        new Thread(() -> {
            System.out.println("Thread2 is start");
            try {
                s1.function2();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("Thread2 is end");

        }).start();

        new Thread(() -> {
            System.out.println("Thread3 is start");
            try {
                s2.function2();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("Thread3 is end");

        }).start();
    }
}
执行结果如下

多个对象执行普通方法结果

丛中可以看出,对象二s2 并没有收到s1的影响,自己个儿跑自己个儿的方法了,所以说synchronized 修饰普通方法,仅仅对该实例对象有限制,其他对象不会有影响。所以锁住的是this 实例对象。

修饰类方法

直接上代码

package com.thread;

public class SynchronizedTest {

    synchronized public static void function1() throws InterruptedException {
        String name = Thread.currentThread().getName();
        for (int i = 0; i < 5; i++){
            System.out.println("function1 " + name);
            Thread.sleep(1000);
        }
    }

    synchronized public static void function2() throws InterruptedException {
        String name = Thread.currentThread().getName();
        for (int i = 0; i < 5; i++){
            System.out.println("function2 " + name);
            Thread.sleep(1000);
        }
    }

    public static void main(String[] args) throws InterruptedException {
        SynchronizedTest s1 = new SynchronizedTest();
        SynchronizedTest s2 = new SynchronizedTest();
        new Thread(() -> {
            System.out.println("Thread1 is start");
            try {
                s1.function1();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("Thread1 is end");

        }).start();

        new Thread(() -> {
            System.out.println("Thread2 is start");
            try {
                s1.function2();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("Thread2 is end");

        }).start();

        new Thread(() -> {
            System.out.println("Thread3 is start");
            try {
                s2.function2();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("Thread3 is end");

        }).start();
    }
}
运行结果如下

synchronized 修饰类方法

可以看出,不同类实例对象的执行按照顺序走了,也就是:虽然是不同的对象,但是s1 s2 都是同一个类的不同对象,这样的话,synchronized 修饰类方法(静态方法),所有对象持有的都是一把锁,也就是SynchronizedTest.class

现有一段代码

public class TestStaticParam {
    private static Integer ticket = 100;
    public void ticket(){
        synchronized (this){
            while (ticket > 0){
                try {
                    Thread.sleep(100);
                    System.out.println(Thread.currentThread().getName()+":"+"减少前:" + ticket +"减少后:"+(--ticket));
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
    }

    public static void main(String[] args) {
        TestStaticParam p1 = new TestStaticParam();
        TestStaticParam p2 = new TestStaticParam();
        new Thread(() -> p1.ticket()).start();
        new Thread(() -> p2.ticket()).start();
    }
}
synchronized 锁住的是this , 该方法是一个普通实例方法,所以this值得也就是实例变量,最后执行的结果肯定有问题!因为所得是实例变量,两个变量互不干扰,肯定影响数据ticket!
如何解决?

1.synchronized this 改成 当前类.class,也就是TestStaticParam .class,这样,按照之前讲过的,该锁就锁住了整个TestStaticParam ,而两个实例变量都是该类产生的,所以,线程跑起来只有线程一 抢到了锁,只想完毕整个循环就结束了!没有线程2什么事

2.synchronized 改成ticket ,这样,锁住的就是 该ticket 对象,两个线程谁抢到该锁,谁就先执行,而synchronized 具有原子性和可见性,从而达到了保护ticket 数据的目的

总结:

synchronized 可以修饰实例方法,也可以修饰静态方法。修饰实例方法的时候,锁住的是this当前对象;修饰类方法(静态方法)的时候,锁住的是XXX.class 也就是当前类

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值