java多线程编程核心技术——第二章

第一节synchronized同步方法目录

 

说到线程安全,就要提到非线程安全问题了:

  “非线程安全问题”:在多个线程同时同一个对象中的实例变量进行访问时发生。产生的结果就是脏读(读到被修改过的数据)。

  “线程安全”获得的实例变量是经过同步处理的,不会出现脏读的情况。

  “非线程安全”的问题存在于实例变量中,如果将实例变量私有,则不存在“非线程安全”问题,所得就是线程安全了。

  注:在方法内部声明变量,是不存在“非线程安全”问题的。原因是:方法内部的变量是私有的特性。

  

 

  如果多个线程同时访问一个对象的实例变量,则可能会出现“非线程安全问题”。

  有多个实例变量可能会出现交叉的情况,如果仅有一个实例变量时可能会出现覆盖的情况。

  若想解决非线程安全问题,需要在对实例变量操作的方法上加synchronized关键字做修饰。

 

  若多个线程,调用多个实例中的同步方法,会发现结果是不同步的。

  原因:关键字synchronized取得的锁时对象锁,而不是一段代码或者一个方法(函数)的锁。

    所以要想实现同步效果,必须是多个线程访问同一个实例中的变量才能够实现。若出现多个线程访问多个实例中的同步方法,自然会发现结果是异步的。

  因为synchronized是给对象上锁的,所以当一个线程获得对象锁的时候(此时该线程必定进入对应的同步方法或者同步代码块),其他线程若想获得同步方法的执行权需要排队等待。

  但是若其他线程调用非synchronized修饰的方法时,则无需排队,可以直接调用。

  简述:

A线程先持有object对象的Lock锁,B线程可以以异步的方式调用object对象中的非synchronized类型的方法。

A线程先持有object对象的Lock锁,B线程如果在这时调用object对象中的synchronized类型的方法时,需要等待,也就是同步。

  脏读:在读取实例变量时,此值已经被其他线程修改过了。

  通常解决方法就是,在实例变量的赋值和获取方法上都使用synchronized修饰,这样就可以实现同步,避免脏读的情况出现。

  关键字synchronized具有锁重入的能力,也就是在使用synchronized时,当一个线程得到一个对象锁后,再次请求此对象锁时是可以再次得到该对象的锁的。这也证明了在一个synchronized方法/块内部调用本地其他synchronized方法/块时,是永远可以得到锁的。

  可重入锁概念:自己可以再次获得自己的内部锁,比如有1条线程获得了某个对象的锁,此时这个对象锁还没有释放,当其再次想要获得这个对象的锁的时候还是可以获得的,如果不可锁重入,会导致进入死循环。

  可重入锁也可以出现在继承中:当存在父子类继承时,子类完全可以使用锁重入调用父类的同步方法。

  当一个线程执行的代码出现异常时,其所持有的锁会自动释放,锁被释放后,其他排队等候的线程就会获得当前的对象锁。

 

  同步是不可以被继承的。

  子类继承了父类,并且重写了父类中的同步方法,若有多线程同时执行子类中的重写方法时,会发现是非同步的。这时如果想要实现同步,必须在子类的方法前加上synchronized。

 第二节synchronized同步语句块目录

 

 

 

  synchronized方法的弊端:代码执行时间过长,占用锁致使其他线程必须排队等待。

  可以通过使用同步代码块来解决这个问题。

  注:就是通过一个例子表现了同步方法会花费很长的时间,不过项目里面具体使用什么应该根据实际需要来考虑。

 

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/wssdgg.html