Java多线程编程核心技术-----第二章读书笔记

2.1.1 
        方法里面的变量是临时变量,在栈内创建。
        多次调用某个方法,则多次创建临时变量,线程安全

2.1.2
        多个线程通过某方法同时操作同一个对象的属性,可能是线程不安全的,需要把操作的方法加上同步锁

2.1.3
        同步方法的同步锁是对象锁锁是当前的对象,效果相当于 synchronized(this){}这样的同步代码块
2.1.4
        原:只有共享资源的读写访问才需要同步化,如果不是共享资源,那么根本没有同步的必要。P61
        这就是为什么要使用同步的原因,没有这个原因,压根不需要同步。

        A线程持有了同步锁,B线程可以调用其它非同步的语句

2.1.5
        脏读是多个线程同时操作共享变量导致的不良结果。
        在获取共享变量的时候,共享变量已经被修改过了。
        在获取值的时候,出现了相关的延迟,用Thread.sleep(X)来模拟。期间值被修改,醒来后再调用变量数据已经变了。
        我们希望的是:获取共享变量的时候值不能被修改,在查询值后,对共享变量的操作期间,不允许被写线程进入。
        所以获取与修改操作应该共享同一把锁

2.1.6
        原:当一个线程在得到对象锁,再次请求该对象锁是可以的。
        在一个线程调用同步方法的同时在其方法体内部调用该对象另一个同步方法,
        也就是说一个线程得到一个对象锁后再次请求该对象锁,是允许的,这就是synchronized锁的可重入性
        synchronized支持锁重入,子类在同步方法内部调用父类的同步方法,也能够进入
        因为每个子类对象都独立的拥有一个属于它自己的父类对象,所以父类的同步方法就是子类自己的同步方法,继承到的同步方法的同步锁,依旧是子类对象,而不是父类对象,否则就不会触发synchronized的锁重入了。

        锁重入的特性是为了解决死锁问题。比如登录中需要验证数据,登录方法和验证方法都是同步方法。如果登录方法获取了同步锁,那么验证方法则不能执行,因为验证方法也是需要同步锁的,这样的话,就会出现死锁。synchronized锁重入就可以解决这个问题,在登录方法中,可以调用其它同步方法。

2.1.7
        线程出现异常会自动释放同步锁。

2.1.8
        同步不能被继承。
        子类在重写父类同步方法的时候,为了保证重写后的方法仍然为同步方法,需要为重写的方法加上synchronized修饰符,来保证同步。

2.2.1
        原文:如果A线程调用同步方法执行一个长时间的任务,那么B线程则必须等待比较长的时间。P71
        使用同步代码块来替代同步方法,只对需要同步的语句进行同步,提高并发效率
        原文:当一个线程访问对象的一个同步代码块时,另外一个线程仍然可以访问该对象的非同步代码块。P76
        同步方法的同步锁是当前对象,而同步代码块的同步锁可以任意指定。

2.2.4
        原文:在同步代码块中的代码是同步执行,不在同步代码块中的代码是异步执行。P76
        异步访问的代码意思是多个线程能够同时访问的代码

2.2.7
        使用同步代码块指定任意对象锁(非this对象),与同步方法的当前对象锁,不是同一把锁。
        因此可以异步进行,增加并发效率。

        线程异步的效果:线程调用方法是无序的,极易出现脏读情况。
        要知道,线程就是用来调用方法的,若这些方法有对共享变量的读写操作,
        极易出现脏读。

2.2.8
        A线程抢夺到了“任意对象锁” ,B线程或其它线程执行另外需要同一把锁的“任意”地方,都需要等待

2.2.9
        静态同步方法的同步锁是当前类的字节码文件,即.class文件。
        即与synchronized(类.class)文件 本质相同。

2.2.10
        避免使用字符串作为同步代码块的同步锁,因为字符串共享常量池

2.2.11
        同步代码块中的同步锁引用指向的是一个堆内存中的对象。只要这个对象所在的内存地址不变
        即使存储的内容有变化,也不影响此对象作为锁的使用。

2.3
        原:关键字volatile修饰变量的作用是:使变量在多个线程间可见,强制线程从公共堆栈中取得变量的值,而不是从线程的私有(内存)数据栈中取得变量的值。(从变量和线程角度分别阐述)P118,P120     
        当前线程从公共内存中读取数据,而不是从私有内存中获取值。
        当前线程在从公共内存中读取数据到私有内存中后,公共内存值被修改了,可能会造成脏读。
        使用volatile关键字后,直接使用的就是公共内存中的最新的值。

        一言以蔽之:volatile修饰的变量,内存存放在公共区,所有线程都能看到。

        原:线程安全包含原子性和可见性两个方面,Java的同步机制都是围绕这两个方面来确保线程安全的。P124
        非原子性语句可能出现线程安全问题,变量可见性用于线程之间的通信。

        原:关键字volatile解决的是变量在多个线程之间的可见性,而synchronized关键字解决的是多个线程之间访问资源的
        同步性。P123

        volatile的作用有两点:(1)从变量和线程的角度分别阐释 (2)让JVM禁止指令重排序优化

        原:volatile关键字最致命的缺点是:不支持原子性
        只保证线程的工作内存中的数据都是最新的,无法保证原子性。所以还需对变量的操作进行加锁。


2.3.5
        i++和 ++j 都是对变量进行自增操作,结果是i和j都自增。但是其表达式的值不一样,前者是i,后者是j+1。

        原:synchronized还具有将线程工作内存中的私有变量与公共内存中的变量同步的功能。P130
        在进入同步代码块之前,更新当前线程的工作内存,保证与公共内存的数据一致。

posted @ 2022-07-17 12:15  小大宇  阅读(19)  评论(0编辑  收藏  举报