线程状态
1.NEW :对象刚创建,还没有在系统中创建线程。即将任务交给线程,但是线程还没开始执行
2.RUNNABLE:线程是一个准备就绪状态
3.BLOCKED/WAITING/TIMED_WAITING:都是表示锁住的状态
4.TERMINATED:表示线程结束
在NEW-TERMINATED过程中正常就是经过NEW—>RUNNABLE(运行)—>READY(就绪)——->TREMINATED(终止)
但是在这之间如果遇到Object.wait()、Object.join()、Lock.Support.Park()就会进入WAITING(等待)状态,需要经过Object.notify(),Object.notifyAll()或者LockSupport.unpark(Thread)解除等待,回到就绪状态。经过Thread.sleep(long),Object.wait(long),Thread.join(long),LockSupport.parkNanos(),LockSupport.parkUnit()使线程进入TIMED WAITING(超时等待),只有经过Object.notify(),Object.notifyAll(),LockSupport.unpark(Thread)解除等待;而在进入synchronized方法或synchorized代码块获得锁,进入BLOCKED(阻塞状态)
线程安全
线程虽然更轻量,但多个线程是访问同一份内存资源,由于线程是一个抢占性的执行过程,不确定因素太多,容易出现Bug,所有线程具有不安全性
线程不安全的因素
1.“抢占式”执行过程:多个线程谁先执行,谁后执行,完全取决于系统的调度器
2.多个线程同时修改同一个变量。
3.修改操作不是原子性。如果把三个操作打包成一个整体,禁止相互穿插执行也能保证线程安全
4.内存可见性。编译器优化导致线程修改的数据没有及时写入内存,其他线程无法读取到数据或读到的是原来的数据
5.指令重排序。也是编译器为了让程序提高执行效率,在保证逻辑不变调整执行的顺序
synchronized-监视器锁monitor lock
1.synchronized—>加锁,保证原子性,同时禁止指令重排序和保证内可见性
2.用于对象①代码块②方法,分别有非静态方法和静态方法,非静态方法相当于加锁对象(this);静态方法对象是类对象
3.如果对一个线程进行加锁后还没来得及解锁,又想对其进行加锁,会出现死锁状态,而关于synchronized死锁,其自身已经考虑到了,即“可重复锁”
当第一次加锁,即记录加锁,之后再加锁时,不是进行二次加锁,而是进行次数++操作,当解锁时也是进行次数–操作,直到等于零(同一个线程下)
4.使用volatile能够禁止重排序,保证内存可见性,但是不保证原子性。如果多个线程同时写操作,则volatile不能保证线程安全