一.关键字
1.synchronized关键字:
a.重量级锁,功能完整的锁
b.修饰类、方法、静态方法、代码块,但不可以在声明的时候修饰
c.synchronized是实现同步的基础,Java中不管是对象还是方法,都可加上锁。synchronized分为三种
对象锁:对于普通同步方法,锁是当前实例对象。
①、在一个线程访问一个对象中一个加synchronized的非静态方法时,会将整个对象都锁住。整个对象中加锁的方法之间都互斥,加锁的和不加锁的不互斥。加锁的方法之间不能在两个线程之间同时运行,需要一个运行完另一个在运行
类锁:对于静态同步方法,锁是当前类的Class对象
①、类锁static,它不属于对象,属于类。static修饰的加锁的互斥
②、对象锁和类锁不互斥,互不干扰。
同步代码块:对于同步方法块,锁是Synchonized括号里配置的对象。
①、锁某一个全局变量,锁住的是变量的值,而不是变量本身
2.volatile关键字:
a.轻量级锁,功能不全的锁
b.只修饰变量,在声明的时候修饰
c.volatile是轻量级的synchronized,它在多处理器开发中保证了共享变量的“可见性”可见性的意思是当一个线程修改一个共享变量时,另外一个线程能读到这个修改的值
d.volitile保障正确的读到(其他线程写完之后可以立刻感知到)及保证了写后读:
导线一次只能通过一组数据,需要排队从高速缓存返回内存,volitile来排队返回的数据中之所以精确的到达内存的这个地址,是因为返回的数据中存有内存地址。volitile实现了返回时告诉缓存,和我相同对应地址的别的线程修改的数据失效了,需要重新计算。volatile将还在计算的数据被销毁,已经计算完毕的进入排队队列的数据不能被销毁。所有volatile不能完全代替synchronized.
volatile只能保证读正确,不能保证写正确
e.volatile防止指令重排序
3.两者区别:
synchronized锁住的元素在高速缓存中只能有一个,在一个线程读写时,其余线程连读都不让读;而volitile只能保证写后读,但往回更新是不能保障的
二、如何避免死锁
- 避免一个线程同时获取多个锁。
- 避免一个线程在锁内同时占用多个资源,尽量保证每个锁只占用一个资源。
- 尝试使用定时锁,使用lock.tryLock(timeout)来替代使用内部锁机制。
- 对于数据库锁,加锁和解锁必须在一个数据库连接里,否则会出现解锁失败的情况。
三、让出cpu的三种方式
- Thread.sleep(0):立即让出CPU,在多少秒内不参与CPU的竞争。然后在数字到0时继续参与竞争。
- Thread.yield():主动让出cpu进入就绪态,但不是立即让出CPU的意思。 但是当我们调用Thread.yield()的那一刻,并不意味着当前线程立马释放cpu资源,这是因为获得时间片的线程从runable切换到running仍需要一定的准备时间,这段时间当前线程仍可能运行一小段时间。
- 我们写多线程的时候不匹配的话直接让出CPU,提高性能