synchronized使用

1、 synchronized关键字使用在方法上面,代码如下

@Slf4j(topic = "test")
public class BasicLock {

    public synchronized void x(){
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        log.debug("x");
    }

    public synchronized void y(){
        log.debug("y");
    }

    public void z(){
        log.debug("z");
    }
}

测试类

@Slf4j(topic = "test")
public class TestBasic2 {
    public static void main(String[] args) {
        BasicLock basicLock = new BasicLock();


        new Thread(()->{
            log.debug("start");
            basicLock.x();
        },"t1").start();

        new Thread(()->{
            log.debug("start");
            basicLock.y();
        },"t2").start();

        new Thread(()->{
            log.debug("start");
            basicLock.z();
        },"t3").start();
    }
}

打印结果如下

第一次执行

16:37:26.219 [t1] DEBUG test - start
16:37:26.219 [t2] DEBUG test - start
16:37:26.219 [t3] DEBUG test - start
16:37:26.224 [t3] DEBUG test - z
16:37:27.224 [t1] DEBUG test - x
16:37:27.224 [t2] DEBUG test - y

第二次执行

16:38:51.772 [t3] DEBUG test - start
16:38:51.772 [t2] DEBUG test - start
16:38:51.772 [t1] DEBUG test - start
16:38:51.777 [t3] DEBUG test - z
16:38:51.777 [t2] DEBUG test - y
16:38:52.777 [t1] DEBUG test - x

第三次执行

16:39:40.283 [t2] DEBUG test - start
16:39:40.283 [t1] DEBUG test - start
16:39:40.283 [t3] DEBUG test - start
16:39:40.287 [t2] DEBUG test - y
16:39:40.287 [t3] DEBUG test - z
16:39:41.288 [t1] DEBUG test - x

三个线程几乎同时启动,由于 x和y方法使用了synchronized 关键字加锁,所以 x和y的打印始终是间隔1秒,而z没有加synchronized关键字进行加锁,所以打印肯定不会超过1秒

 

2、synchronized 对两个对象进行加锁

新增一个类

@Slf4j(topic = "test")
public class BasicLock1 {

    public synchronized static void x(){
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        log.debug("x");
    }

    public synchronized void y(){
        log.debug("y");
    }

    public void z(){
        log.debug("z");
    }
}

测试类

@Slf4j(topic = "test")
public class TestBasic3 {
    public static void main(String[] args) {
        BasicLock basicLock = new BasicLock();
        BasicLock basicLock1 = new BasicLock();

        new Thread(()->{
            log.debug("start");
            basicLock.x();
        },"t1").start();

        new Thread(()->{
            log.debug("start");
            basicLock1.y();
        },"t2").start();


    }
}

测试类中 进行加锁的是两个对象,所以两个线程的执行互不影响

打印如下

16:51:59.416 [t2] DEBUG test - start
16:51:59.416 [t1] DEBUG test - start
16:51:59.421 [t2] DEBUG test - y
16:52:00.422 [t1] DEBUG test - x

3、synchronized 对静态方法加锁和对普通方法加锁的区别

测试类(锁对象继续使用上文中的 BasicLock1)

@Slf4j(topic = "test")
public class TestBasic4 {
    public static void main(String[] args) {
        BasicLock1 basicLock1 = new BasicLock1();


        new Thread(()->{
            log.debug("start");

            basicLock1.x();
        },"t1").start();

        new Thread(()->{
            log.debug("start");

            basicLock1.y();
        },"t2").start();


    }
}

打印结果

16:53:03.465 [t1] DEBUG test - start
16:53:03.465 [t2] DEBUG test - start
16:53:03.469 [t2] DEBUG test - y
16:53:04.470 [t1] DEBUG test - x

4、synchronized 对同一个类的不同的静态方法加锁

@Slf4j(topic = "test")
public class BasicLock2 {

    public synchronized static void x(){
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        log.debug("x");
    }


    public synchronized static void y(){
        log.debug("y");
    }

    public void z(){
        log.debug("z");
    }
}

测试类

@Slf4j(topic = "test")
public class TestBasic5 {
    public static void main(String[] args) {
        BasicLock2 basicLock2 = new BasicLock2();

        new Thread(()->{
            log.debug("start");
            basicLock2.x();
        },"t1").start();

        new Thread(()->{
            log.debug("start");
            basicLock2.y();
        },"t2").start();


    }
}

打印如下

16:56:27.380 [t2] DEBUG test - start
16:56:27.380 [t1] DEBUG test - start
16:56:27.384 [t2] DEBUG test - y
16:56:28.385 [t1] DEBUG test - x

16:56:40.872 [t1] DEBUG test - start
16:56:40.872 [t2] DEBUG test - start
16:56:41.875 [t1] DEBUG test - x
16:56:41.875 [t2] DEBUG test - y

总结如下

1、

/**
 * synchronized关键字
 * synchronized关键字锁定的是对象不是代码块,demo中锁的是object对象的实例
 * 锁定的对象有两种:1.类的实例 2.类对象(类锁)
 * 加synchronized关键字之后不一定能实现线程安全,具体还要看锁定的对象是否唯一。
 */
@Slf4j(topic = "test")
public class Demo1 {

    private int count = 10;
    private Object object = new Object();

    public void test(){
        synchronized (object){
            count--;
            log.debug(Thread.currentThread().getName() + " count = " + count);
        }
    }

}

2、

@Slf4j(topic = "test")
public class Demo2 {

    private int count = 10;

    public  void test(){
        //synchronized(this)锁定的是当前类的实例,这里锁定的是Demo2类的实例
        synchronized (this){
            count--;
            log.debug(Thread.currentThread().getName() + " count = " + count);
        }
    }

}

3、

@Slf4j(topic = "test")
public class Demo3 {

    private int count = 10;

    //直接加在方法声明上,相当于是synchronized(this)
    public synchronized void test(){
        count--;
        log.debug(Thread.currentThread().getName() + " count = " + count);
    }

}

4、

@Slf4j(topic = "test")
public class Demo4 {

    private static int count = 10;

    //synchronize关键字修饰静态方法锁定的是类的对象
    public synchronized static void test(){
        count--;
        log.debug(Thread.currentThread().getName() + " count = " + count);
    }

    public static void test2(){
        synchronized (Demo4.class){//这里不能替换成this
            count--;
        }
    }

}
synchronized 关键字使用应注意的地方

1、

**
 * 锁对象的改变
 * 锁定某对象o,如果o的属性发生改变,不影响锁的使用
 * 但是如果o变成另外一个对象,则锁定的对象发生改变
 * 应该避免将锁定对象的引用变成另外一个对象
 */
@Slf4j(topic = "test")
public class Demo1 {

    Object o = new Object();

    public void test(){
        synchronized (o) {
            //t1 在这里无线执行
            while (true) {
                try {
                    TimeUnit.SECONDS.sleep(1);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                log.debug(Thread.currentThread().getName());
            }
        }
    }

    public static void main(String[] args) {
        Demo1 demo = new Demo1();

        new Thread(demo :: test, "t1").start();

        try {
            TimeUnit.SECONDS.sleep(3);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        Thread t2 = new Thread(demo :: test, "t2");

        demo.o = new Object();
        //t2能否执行?
        t2.start();
    }

}

2、

/**
 * 不要以字符串常量作为锁定的对象
 *
 */
@Slf4j(topic = "enjoy")
public class Demo2 {

    String s1 = "hello";

    String s2 = "hello";

    public void test1(){
        synchronized (s1) {
           log.debug("t1 start...");
            try {
                TimeUnit.SECONDS.sleep(5);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            log.debug("t1 end...");
        }
    }

    public void test2(){
        synchronized (s2) {
            log.debug("t2 start...");
        }
    }

    public static void main(String[] args) {
        Demo2 demo = new Demo2();
        //啓動t1
        new Thread(demo :: test1,"t1").start();
        //启动t2
        new Thread(demo :: test2,"t2").start();
    }

}

3、

/**
 * 同步代码快中的语句越少越好
 * 比较test1和test2
 * 业务逻辑中只有count++这句需要sync,这时不应该给整个方法上锁
 * 采用细粒度的锁,可以使线程争用时间变短,从而提高效率
 */
@Slf4j(topic = "enjoy")
public class Demo3 {

    int count = 0;

    public synchronized void test1(){
        try {
            TimeUnit.SECONDS.sleep(2);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        count ++;

        try {
            TimeUnit.SECONDS.sleep(2);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }


    /**
     * 局部加锁
     */
    public void test2(){
        try {
            TimeUnit.SECONDS.sleep(2);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        synchronized (this) {
            count ++;
        }

        try {
            TimeUnit.SECONDS.sleep(2);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

}

 

 

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值