线程:分为守护线程和用户线程
用户线程:当一个进程不包含任何的存活的用户线程,进程结束
守护线程:守护用户线程的,当最后一个用户线程结束时,所有守护线程自动死亡
守护线程是依赖于用户线程,用户线程退出了,守护线程也就会退出,典型的守护线程如垃圾回收线程。
用户线程是独立存在的,不会因为其他用户线程退出而退出。
默认情况下启动的线程是用户线程,通过setDaemon(true)将线程设置成守护线程,这个函数务必在线程启动前进行调用,否则会报java.lang.IllegalThreadStateException异常,启动的线程无法变成守护线程,而是用户线程。
在线程启动之后设置为守护线程,运行出现IllegalThreadStateException
设置线程的守护线程必须在启动之前就设置
当主线程结束之后,紧接着守护线程也就自动结束了
线程不安全的原因:多个线程去争取一个数据,导致线程获得的值跟实际的值有偏差,运行结果不符合预期
解决线程不安全的问题: 线程同步
线程同步的方法一:修饰代码块
注意这里的Object o,一定要是只有一个,不能所有的线程在运行时都创建一个,这样每个线程都有各自的锁,就锁不住其他线程。必须是所有线程公用一把锁,当其中一个线程进入同步代码快时,其他线程没有或得锁就不能进入
格式:
synchronzied(o){
同步代码块;
}
比如:这么一个加锁的代码
反编译的结果:
线程同步的方法二:修饰方法
使用的是同步方法,在方法的前面加上synchronized,注意同步方法锁的对象是this,方法是在类里面被调用的,那么锁的对象就是类的this,静态类就是锁的类.class
如果 在一个类中有多个方法都使用了同步方法,那么其中一个同步方法在执行的时候,其他的方法这个时候只能处于等待的状态,执行不了,因为获取不到锁,所有的同步方法等的都是同一把锁
线程的同步的方法一 和方法二 都属于 隐式锁
有隐式锁肯定就有显式锁
显式锁的使用:
创建出一个锁
在需要加锁的代码前,开启锁
结束时,关闭锁
隐式锁(又称为监视器锁)和显式锁的比较
上面介绍了隐式锁的使用,接下来我们就看看两者的区别吧
Sync是隐式锁。Lock是显示锁
所谓的显示和隐式就是在使用的时候,使用者要不要手动写代码去获取锁和释放锁的操作。
我们大家都知道,在使用sync关键字的时候,我们使用者根本不用写其他的代码,然后程序就能够获取锁和释放锁了。那是因为当sync代码块执行完成之后,系统会自动的让程序释放占用的锁。Sync是由系统维护的,如果非逻辑问题的话话,是不会出现死锁的。
在使用lock的时候,我们使用者需要手动的获取和释放锁。如果没有释放锁,就有可能导致出现死锁的现象。手动获取锁方法:lock.lock()。释放锁:unlock方法。需要配合tyr/finaly语句块来完成。