yield方法的作用是放弃当前的CPU资源,让CPU在次分配时间片,但放弃的时间不确定,有可能刚刚放弃,马上又获得了时间片。
线程的优先级,在操作系统中,线程可以划分优先级,优先级较高的线程可以得到CPU资源较多,设置线程优先级有助于帮"线程规划器"确定在下一次选择哪一个线程来优先执行。可以使用setPriority()方法来设置。
线程的优先级具有继承性,比如A线程启动了B线程,则B线程的优先级与A是一样的。
高优先级的线程总是大部分先执行完,但不代表高优先级的线程全部先执行完。与代码的执行顺序的关系不大。优先级也有不确定性。
在Java线程中有两种线程,一种是用户线程,另一种是守护线程。守护线程是一种特殊的线程,当进程中不存在非守护线程,则守护线程自动销毁。典型的守护线程是垃圾回收线程,当进程中没有非守护线程了,则垃圾回收也没有任何存在的必要了。
非线程安全问题存在于"实例变量"中,如果是方法内部的私有变量,就是在方法内部声明一个变量时,是不存在"非线程安全"问题的。
如果多个线程共同访问一个对象中的实例变量,则有可能出现"非线程安全"问题。
如果两个线程分别访问同一个类的两个不同实例的相同名称的同步方法,结果会以异步的方式运行。原因是由于创建了两个业务对象,在系统中产生了两个锁。
关键字synchronized取得的锁都是对象锁,而不是把一段代码或者方法当作锁。调用关键字synchronized声明的方法一定是排队运行的。
当A线程调用某对象加入Synchronized关键字的X方法时,A线程就获得了X的方法锁,更确切的说是对象的锁,所以其他线程必须等A执行完毕后才可以调用X方法,但可以调用其他非Synchronzied方法。
如果某个对象有两个同步方法X,Y。 A线程先获得了X方法所在对象的锁,所以其他线程必须等A线程执行完毕才可以调用X方法,如果B线程想调用Y方法,也必须等待A线程将X方法执行完毕,也就是释放了对象锁后才可以调用。
Synchronized锁重入,关键字Synchronized拥有锁重入功能,也就是在使用Synchronized时,当一个线程获得一个对象锁后,在此请求此对象锁时是可以在此得到该对象锁的。这也证明在一个Synchronized方法/块的内部调用本类的其他Synchronized方法/块时,是永远可以得到锁的。
可重入锁的概念是:自己可以在此获得自己的内部锁。比如有一个线程获得了某个对象的锁,此时这个对象锁还没有释放,当他想要获取这个对象的锁的时候还是可以获取的,如果不可锁重入的话,就会造成死锁。可重入锁同样适用于父子类继承的关系,当存在父子类继承关系时,子类是完全可以通过"可重入锁"调用父类的同步方法的。
线程执行出现异常后,锁会被自动释放掉。同步方法或者Synchronized时不能被继承的。
多个线程调用同一个对象中的不同名称的Synchronized同步方法或Synchronized(this)同步代码块时,调用的结果就是按顺序执行,也就是同步的,阻塞的。
Synchronized(非this对象x)格式的写法是将x对象本身作为"对象监视器",这样就可以得出以下三个结论:
当多个线程同时执行Synchronized(x){}同步代码块时呈同步效果。
当其他线程执行x对象中Synchronized同步方法时呈同步效果。
当其他线程执行x对象方法里面的Synchronized(this)代码块时也呈现同步效果。
静态同步Synchroni方法与Synchronized(Class)代码块。关键字Synchronized还可以应用在Static静态方法上,如果这样写,那是对当前*.java文件对应的Class类进行持锁。
Synchronized关键字加到static静态方法上是给Class类上锁,而Synchr加到非静态方法上是给对象上锁。
数据类型String的常量池特性。在JVM中具有String常量池缓存的功能。
上面这段代码输出的结果为true,说明a和b是同一个对象。将Synchronized(String)同步块与String联合使用时,要注意常量池带来的一些例外。
Synchronized方法如果长时间不释放锁的话,容易造成另一个等待的线程死锁。死锁是程序设计的Bug,在设计时要避免双方互相持有对方锁的情况。可以用jps和jstack来查看死锁的信息。
在将任何数据类型作为同步锁时,需要注意的是,是否有多个线程同时持有锁对象,如果同时持有相同的锁对象,则这些线程之间就是同步的,如果分别获得锁对象,这些线程之间就是异步的。
Volatile关键字
关键字Volatile的主要作用是使变量在多个线程间可见。
在开发环境运行时线程可以被正常停止,但是如果把JVM设置为Server模式,程序就出现了死循环。原因是这个变量本来存在于公共堆栈和线程私有堆栈中。设置这个变量为false,虽然被执行了,更新的确实公共堆栈中的值,但是私有堆栈没有被更新,所以一直是死循环的状态。
这个问题其实就是私有堆栈中的值和公共堆栈中的值不同造成的,解决这样的问题需要使用volatile关键字,他的主要作用就是线程访问这个变量时,强制性的从公共堆栈或者主存中取值。
使用volatile关键字增加了实例变量在多个线程之间的可见性,但他的缺点是不支持原子性。
Synchronized和volatile的比较:
1)关键字volatile是线程同步的轻量级实现,所以volatile性能比Synchronized要好,而且volatile只能用于修饰变量,而Synchronized可以修饰方法,和代码块,随着JDK新版本的发布,Synchronized的执行效率得到了很大的提升。
2)多线程访问volatile不会发生阻塞,而Synchronized会出现阻塞。
3)volatile能保证可见性,但不能保证原子性。Synchronized都可以。