主要课程的部分内容
多线程共享cpu出现的问题:
出现问题的原因是,每次的加操作不是一条指令,而是多条指令,如果是多条指令的话就有可能被打断,并且篡改变量的值。
共享资源读的时候是没问题的,写的时候是有问题。
如何避免竞争状态?
第一个问题,如果是放在外面就是让五千行代码执行完之后再执行别的线程的代码
第二个问题,两个保护的是两个对象,这样的话就无法保证一个资源同一时间内只有一个线程在使用。
第三个问题:不可以,要对临界区进行保护,需要对使用这个对象的所有的线程都加锁。
锁对象面向对象升级:
方法上的synchronized关键字:加在方法上也是要锁对象或者是锁住类。
线程八锁
第一问:这题考察的是线程和线程之间没有串行关系,有可能第二个线程先抢到时间怕片:
第二问:看哪个线程先抢到时间片
第三问:由于第三个线程没加锁,3是并行执行的。
第四问:这道题的加锁的两个对象不同,所以还是要并行执行。
第五问:这里的两个方法一个有static一个没有static因此一个锁对象,一个锁类对象,所以两个还是并行执行。
第六问:锁住同一个对象,两个线程争抢时间片。
第七问:并行执行
第八问:锁住同一个类对象所以只能同一时间执行一个。
4.4变量的线程安全分析
成员变量不安全的例子
解决方法
答案:不会出现线程安全的问题。
但是如果添加子类会出现线程安全的问题。
下面的get和put两个方法组合起来就不是安全的了。
观看两个线程不安全的例子
这个例子里的成员变量count可能会被多个线程同时修改。
这个例子中的AOP过程中单例的成员变量是被共享的。
这个例子虽然有成员变量,但是因为成员变量是私有的,并且成员变量指向的类没有成员变量,所以这个例子也是线程安全的
这个例子是线程不安全的以为conn变量是被共享的应该写成是局部变量
这里的例子是线程安全的,因为每个对象单独创建了一个UserDao对象,就不存在多个线程同时争夺一个成员变量的问题:
4.6 Monitor概念
Synchronized是如何实现的
首先当一个对象obj加锁之后,obj的markword会指向操作系统中的monitor,一个线程Thread-2占据这个锁,此时这个线程就会占有owner,这时如果又来了其他线程EntryList会指向后来的线程进行等待,后面的线程进入了阻塞状态。
通过交换锁记录地址可以让对象知道哪个线程锁住了他。cas是原子性的锁交换操作。
撤销偏向锁:
锁消除:当加不加锁效果一致的时候就要进行锁消除。
wait和notify
wait和notify的正确使用方法
这里注意notify只能随机唤醒一个线程,而不是挑一个指定的线程唤醒。存在唤醒不满足条件的线程称之为虚假线程,所以需要使用waitnotifyall()
标准的使用notify的格式
模式之保护性暂停
实例:讲一个线程从百度下载的资源传到guardedObject然后再用另外一个线程来接收GuardedObject中的资源,这样的话就可以实现保护性暂停。
保护性暂停之扩展增加时长。
在guardedObject修改等待的时间
join的原理:
futures的实现:
邮箱类:
异步模式之生产者消费者
测试代码:
4.9park and unpark
使用Locksupport类来调用park和unpark
reentrantlock类似于synchronized关键字:
多个条件变量,相当于是多个waitset集合。
reentrantlock锁是创建出来的,本身就是一一把锁对象,调用reentrantlock对象.lock()的方式加锁。
不同于synchronized关键字,这里的临界区保护被try块保护起来了,而不是sychronized(对象)的方式进行保护临界区。
条件变量:reentrantlock得多个条件变量:
4.10顺序控制:
保证t1后于t2运行:
实现相同的顺序实现功能:
交替执行,交替输出:
测试代码
交替输出实现第二种方法: