您的位置:首页 > 编程语言 > Java开发

Java多线程编程核心技术 —— 对象及变量的并发访问

2018-11-17 10:20 253 查看
版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/lkp1603645756/article/details/84063647

1、方法内的变量为线程安全。“非线程安全”问题存在于“实例变量”中,如果是方法内部的私有变量,则不存在“非线程安全”问题,所得结果也就是“线程安全”的了。

 

2、如果多个线程共同访问1个对象中的实例变量,则有可能出现“非线程安全”问题。

 

3、关键字synchronized取得的锁都是对象锁,而不是把一段代码或方法(函数)当作锁,所以在上面的示例中,哪个线程先执行带synchronized关键字的方法,哪个线程就持有该方法所属对象的锁Lock,那么其他线程只能呈等待状态,前提是多个线程访问的是同一个对象。但如果多个线程访问多个对象,则JVM会创建多个锁。

 

4、多个线程调用同一个方法时,为了避免数据出现交叉的情况,使用synchronized关键字来进行同步。虽然在复制时进行了同步,但在读取值时可能出现一些意想不到的以外,这种情况就是脏读。发生脏读的情况是在读取实例变量时,此值已经被其他线程更改过了。

 

5、脏读是通过synchronized关键字解决的。脏读一定会出现操作实例变量的情况下,这就是不同线程“争抢”实例变量的结果。

 

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

 

7、“可重入锁”的概念是:自己可以再次获取自己的内部锁。比如有1条线程获得了某个对象的锁,此时这个对象锁还没有释放,当其再次想要获取这个对象的锁的时候还是可以获取的,如果不可锁重入的话,就会造成死锁。

 

8、当存在父子继承关系时,子类是完全可以通过“可重入锁”调用父类的同步方法的。

 

9、当一个线程执行的代码出现异常时,其所持有的锁会自动释放。

 

10、同步不具有继承性,就是同步不可以继承。

 

11、在使用同步synchronized(this)代码块时需要注意的是,当一个线程访问object的一个synchronized(this)同步代码块时,其他线程对同一个object中所有其他synchronized(this)同步代码块的访问将被阻塞,这说明synchronized使用的“对象监视器”是一个。

 

12、和synchronized方法一样,synchronized(this)代码块也是锁定当前对象的。

 

13、“synchronized(非this对象x)”格式的写法是将x对象本身作为“对象监视器”,这样就可以得出以下3个结论:

1)当多个线程同时执行synchronized(x){}同步代码块时呈同步效果。

2)当其他线程执行x对象中的synchronized同步方法时呈同步效果。

3)当其他线程执行x对象方法里面的synchronized(this)代码块时也呈现同步效果。

但需要注意:如果其他线程调用不加synchronized关键字的方法时,还是异步调用。

 

14、关键字synchronized还可以应用在static静态方法上,如果这些写,那是对当前的*.java文件对应的Class类进行持锁。

 

15、synchronized关键字加到static静态方法上是给Class类上锁,而synchronized关键字加到非static静态方法上是给对象上锁。

 

16、Class锁可以对类的所有对象实例起作用。

 

17、同步synchronized(class)代码块的作用和synchronized static方法的作用一样。

 

18、在JVM中具有String常量池缓存的功能,所以下图所示的结果为true。

 

19、将synchronized(String)同步快与String联合使用时,要注意常量池以带来的 一些例外。如果两个线程传入的String是相同的,那么两个线程持有相同的锁,会造成另一个线程不能执行。这就是String常量池所带啦的问题。因此在大多数的情况下,同步synchronized代码块都不使用String作为锁对象,而改用其他,比如new Object()实例化一个Object对象,但它并不放入缓存中。

 

20、同步方法容易造成死循环,这时就可以使用同步块来解决这样的问题。

 

21、Java线程死锁是一个经典的多线程问题,因为不同的线程都在等待根本不可以被释放的锁,从而导致所有的任务都无法继续完成。在多线程技术中,“死锁”是必须避免的,因为这会造成线程的“假死”。

 

22、内置类中有两个同步方法,如果使用的是不同的锁,那么打印的结果也是异步的。

 

23、同步代码块synchronized(class2)对class2上锁后,其他线程只能以同步的方式调用class2中的静态同步方法。

 

24、在将任何数据类型作为同步锁时,需要注意的是,是否有多个线程同时持有锁对象,如果同时持有相同的锁对象,则这些线程之间就是同步的;如果分别获得锁对象,这些线程之间就是异步的。

 

24、在将任何数据类型作为同步锁时,需要注意的是,是否有多个线程同时持有锁对象,如果同时持有相同的所对象,则这些线程之间就是同步的;如果分别获得锁对象,这些线程之间就是异步的。只要对象不变,即使对象的属性被改变,运行的结果还是同步的。

 

25、volatile关键字的主要作用是使变量在多个线程间可见。

 

26、如果不是在多继承的情况下,使用继承Thread类和实现Runnable接口在取得程序运行的结果上并没有什么太大的区别。如果一旦出现“多继承”的情况,则用实现Runnable接口的方式来处理多线程的问题就是很有必要的。

 

27、使用volatile关键字可以解决私有堆栈中的值和公共堆栈中的值不同步的问题。它的主要作用就是当线程访问被它修饰的变量时,强制性从公共堆栈中进行取值。使用volatile关键字增加了实例变量在多个线程之间的可见性。但volatile关键字最致命的确定是不支持原子性,也不具备同步性。

 

28、synchronized和volatile比较:

1)关键字volatile是线程同步的轻量级实现,所以volatile性能肯定比synchronized要好,并且volatile只能修饰于变量,而synchronized可以修饰方法,已经代码块。随着JDK新版本的发布,synchronized关键字在执行效率上得到很大提升,在开发中使用synchronized关键字的比率还是比较大的。

2)多线程访问volatile不会发生阻塞,而synchronized会出现阻塞。

3)volatile能保证数据的可见性,但不能保证原子性;而synchronized可以保证原子性,也可以间接保证可见性,因为它会将私有内存和公共内存中的数据做同步。

4)再次重申一下,关键字volatile解决的是变量在多个线程之间的可见性;而synchronized关键字解决的是多个线程之间访问资源的同步性。

线程安全包含原子性和可见性两个方面,Java的同步机制都是围绕这两个方面来确保线程安全的。

 

29、除了在i++操作时使用synchronized关键字实现同步外,还可以使用AtomicInteger原子类进行实现。

原子操作时不能分割的整体,没有其他线程能够中断检查正在原子操作中的变量。一个原子类型就是一个原子操作可用的类型,它可以在没有锁的情况下做到线程安全。

 

30、关键字synchronized可以使用多个线程访问同一个资源具有同步性,而且它还具有将线程工作内存中的私有变量与公共内存中的变量同步的功能。

 

31、关键字synchronized可以保证在同一个时刻,只有一个线程可以执行某一个方法或某一个代码块。它包含两个特征:互斥性和可见性。同步synchronized不仅可以解决一个线程看到对象处于不一致的状态,还可以保证进入同步方法或者同步代码块的每个线程,都看到由同一个锁保护之前所有的修改状态。

 

 

学习多线程并发,要着重“外练互斥,内修可见”,这是掌握多线程、学习多线程并发的重要技术点。

阅读更多
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐