Java并发编程——synchronized解决线程同步问题

线程安全问题的例子

下面示例没有线程同步,出现了脏读现象。线程A调用setValue取得了publicVarRef对象锁,但是线程A仍然可以调用publicVarRef对象的非synchronized方法getValue()。

public class Runner {
    public static void main(String[] args) {
        try {
            PublicVar publicVarRef = new PublicVar();
            ThreadA threadA = new ThreadA(publicVarRef);
            threadA.start();
            Thread.sleep(100);
            publicVarRef.getValue();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

class PublicVar {
    public String username = "A";
    public String password = "AA";

    synchronized public void setValue(String username, String password) {
        try {
            this.username = username;
            Thread.sleep(5000);
            this.password = password;
            System.out.println("setValue thread name=" + Thread.currentThread().getName() +
                    " username=" + username +
                    " password=" + password);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

     public void getValue() {
        System.out.println("getValue thread name=" + Thread.currentThread().getName() +
                " username=" + username +
                " password=" + password);
    }
}

class ThreadA extends Thread {
    private PublicVar publicVar;

    public ThreadA(PublicVar publicVar) {
        super();
        this.publicVar = publicVar;
    }

    @Override
    public void run() {
        super.run();
        publicVar.setValue("B", "BB");
    }
}

运行结果:

getValue thread name=main username=B password=AA
setValue thread name=Thread-0 username=B password=BB

如果public void getValue()方法加上synchronized修饰,则没有脏读了,因为必须等待执行完setValue才能调用getValue。结果如下:

setValue thread name=Thread-0 username=B password=BB
getValue thread name=main username=B password=BB

synchronized的锁是什么

关键字 synchronized 取得的锁是对象锁,而不是把一段代码或方法当做锁。哪个线程先执行带synchronized关键字的方法,哪个线程就持有该方法所属对象的锁Lock,那么其他线程只能等待,前提是多个线程访问的是同一个对象。如果多个线程访问多个对象,则JVM会创建多个锁。、

synchronized 几种情况的对象锁:

  • synchronized非静态同步方法,对象锁是this
  • synchronized静态同步方法,对象锁是类名.class
  • synchronized (obj) {} 同步代码块,对象锁是obj

下面两个方法是类似的,synchronized修饰静态方法和synchronized (Service.class){}代码块的对象锁都是Service.class

class Service {
    public synchronized static void foo(){
        
    }
    
    public static void foo2(){
        synchronized (Service.class){
            
        }
    }
}

synchronized的一些特性

  1. 出现异常,锁自动释放
    当线程执行的代码出现异常时,其所持有的锁会自动释放
  2. synchronized修饰方法不具有继承性
    子类重写父类synchronized修饰的方法,需要在子类方法添加synchronized关键字
  3. synchronized锁重入
    自己可以再次获取自己的内部锁。比如有一个线程获取了某个对象锁,此时这个对象锁还没有释放,当其再次想要获得这个对象的锁的时候还是可以获取的,如果不可锁重入的话就会造成死锁。
    // synchronized锁重入
    public class Runner {
        public static void main(String[] args) {
            MyThread myThread = new MyThread();
            myThread.start();
        }
    }
    
    
    class Service {
    	// 可以再次获取自己的内部锁
        synchronized public void service1() {
            System.out.println("service1");
            service2();
        }
    
        synchronized public void service2() {
            System.out.println("service1");
            service3();
        }
    
        synchronized public void service3() {
            System.out.println("service3");
        }
    
    }
    
    class MyThread extends Thread {
        @Override
        public void run() {
            super.run();
            Service service = new Service();
            service.service1();
        }
    }
    
  4. synchronized有volatile同步的功能
    关键字synchronized具有可视性,可以使多个线程访问同一资源具有同步性,而且它还具有将线程工作内存中的私有变量与公共内存中的变量同步的功能,这可以保证进入同步方法或代码块的每个线程,都看到由同一个锁保护之前所有的修改效果。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值