多线程学习
多线程可能并不快(假如有锁,存在上下文切换。当然更多的是快的,因为CPU并不是一直执行,CPU歇着的时候,其他线程运行,如果是串行,CPU歇着目前就是歇着,执行到下一句了,在开始工作),但是有些事可能并不是顺序发生,所以需要多线程。
线程(Thread)是一份独立运行的程序,有自己专用的运行栈。
线程有可能和其他线程共享一些资源,比如,内存,文件,数据库等。
当多个线程同时读写同一份共享资源的时候,可能会引起冲突。
这时候,我们需要引入线程“同步”机制(”锁”),即各位线程之间要有个先来后到,不能一窝蜂挤上去抢作一团。
线程状态:
NEW:
新创建了一个线程对象。
RUNNABLE:
线程对象创建后,其他线程调用了该对象的start()方法。该状态的线程位于“可运行线程池”中,变得可运行,只等待获取CPU的使用权。
即在就绪状态的进程除CPU之外,其它的运行所需资源都已全部获得。BLOCKED:
一个阻塞线程在等待monitor锁。阻塞状态是线程因为某种原因放弃CPU使用权,暂时停止运行。直到线程进入就绪状态,才有机会转到运行状态。
WAITING:
一个线程在等待另一个线程执行一个动作时在这个状态。调用了Wait方法或者join方法
TIMED_WAITING:
一个线程在一个特定的等待时间内等待另一个线程完成一个动作会在这个状态,sleep,wait,join方法
TERMINATED:
结束
注:
当线程刚进入可运行状态(注意,还没运行),发现将要调用的资源被synchroniza(同步),获取不到锁标记,将会立即进入锁池状态,
等待获取锁标记(这时的锁池里也许已经有了其他线程在等待获取锁标记,这时它们处于队列状态,既先到先得),一旦线程获得锁标记后,就转入就绪状态,等待OS分配CPU时间片;
线程常用方法:
- currentThread.sleep():
anotherThread.join():
进程让出CPU,然后就会进入阻塞状态(该状态既停止当前线程,但并不释放所占有的资源,线程不会释放它的“锁标志”。)
当sleep()结束或join()结束后,该线程自动进入可运行状态,继续等待OS分配CPU时间片currentThread.yield():
放弃当前获得的CPU时间片,回到就绪状态,这时与其他进程处于同等竞争状态,OS有可能会接着又让这个进程进入运行状态;
调用 yield() 的效果等价于调度程序认为该线程已执行了足够的时间片从而需要转到另一个线程。yield()只是使当前线程重新回到可执行状态,所以执行yield()的线程有可能在进入到可执行状态后马上又被执行。currentThread.interrupt():
此操作会中断等待中的线程,并将线程的中断标志位置位。如果线程在运行态则不会受此影响。
1)currentThread.interrupt():
此操作会中断等待中的线程,并将线程的中断标志位置位。如果线程在运行态则不会受此影响。
isInterrupted()
此方法只会读取线程的中断标志位,并不会重置。
2)interrupted()
此方法读取线程的中断标志位,并会重置。
3)throw InterruptException
抛出该异常的同时,会重置中断标志位。currentThread.suspend()和currentThread.resume()
两个方法配套使用,suspend()使得线程进入阻塞状态,并且不会自动恢复,必须其对应的resume()被调用,才能使得线程重新进入可执行状态。典型地,suspend()和 resume() 被用在等待另一个线程产生的结果的情形:测试发现结果还没有产生后,让线程阻塞,另一个线程产生了结果后,调用 resume()使其恢复。 suspend在调用过程中不会释放所占用的锁
只有成功获取了signal这个信号量兼同步锁之后,我们才可能调用singal.方法
signal.wait():
运行这段代码的当前线程开始wait这个signal对象,即进入signal对象的待召(Waiting)队列。
wait()还可以定义等待时间,当线程在某信号量的待召队列中,等到足够长的时间,就会等无可等,无需再等,自己就从待召队列转移到就绪队列中了.线程会释放掉它所占有的“锁标志”.waite()和notify()因为会对对象的“锁标志”进行操作,所以它们必须在synchronized函数或synchronizedblock中进行调用。如果在non-synchronized函数或non-synchronizedblock中进行调用,虽然能编译通过,但在运行时会发生IllegalMonitorStateException的异常。- signal.notify():
这里,我们通知signal的待召队列中的某个线程。如果某个线程等到了这个通知,那个线程就会转到就绪队列中.但是本线程仍然继续拥有signal这个同步锁,本线程仍然继续执行
- signal.notify():
锁的分类
按照轻重来分:
- 无锁状态
- 偏向锁状态
- 轻量级锁状态
- 重量级锁状态
他们会随着竞争的激烈而逐渐升级。注意锁可以升级不可降级,这种策略是为了提高获得锁和释放锁的效率。
参考文章
线程的几种状态转换
为什么要线程同步
线程的几种状态转换以及方法