线程的六种状态
1.NEW:线程刚刚创建,还未启动时的状态。
2.RUNNABLE:线程在JAVA虚拟机中执行的状态。
3.BLOCKED:线程被阻塞等待监视器锁定的状态。
线程休眠【sleep(),sleep(long millis),sleep(long millis, int nanos)
】:程序的执行是非常快的,如果有时候我们需要程 序一秒才执行一次,这个时候,就需要运用到系统的休眠。例如:
这样程序就是没间隔一秒输出一个值。
线程阻塞:所有需要耗费时间的操作,例如:读取文件、接受用户输入;线程阻塞不仅仅是只有线程休眠。线程安全问题:当一个程序有多个线程同时执行时,就会容易出现线程安全问题,就会导致数据错乱或者丢失的情况,例如:执
行一个买票的程序
主函数:
结果:
由此可以看出,余票出现了负数的情况,按逻辑来说,当余票为0时,将不在执行循环,之所以产生这种原因是因为,几个程序在同时走这一个方法,当先进来的几个线程还么有执行完成,后面的线程就也进入了循环,导致
后面余票只剩下一张的时候,第一个线程进入判断,之后开始买票,但是买票操作还没有完成,后面两个线程也先后进入判断,因为最开始的进入的线程还没有执行完成,余票还是剩下1,所以剩下两个线程也会进入循环,
导致后面余票出现了负数的存在。
处理线程安全的三个方法:可以让线程都排队执行
(A,B都问隐式锁)
A、同步代码块(synchronized):每进去一个线程,都会对那个对象打一个标记,这样,其他的线程就不能进去执行代码块,只有当进去的那一个线程执行完毕,然后释放锁,那行等待的锁会对锁进行一
个争抢,抢到锁的又继续进行之前的操作,但是多个线程执行这个代码块,不能有多个锁对象,否则还是会出现线程不安全问题。
格式:synchronized(锁对象){
代码块
}
B、同步方法块(synchronized):对一个方法进行加锁,而同步代码块是比较细致的对几个代码进行加锁,原理还是跟同步代码块类似。
注意:他的锁就是this,谁调用了这个方法就是谁,如果是静态修饰的就是类名.class。
格式:public synchronized 返回值类型 方法名(){
}
C、显示锁Lock:Lock 子类 ReentrantLock,创建对象,自己锁,执行完自己解锁。
格式:Lock l = new ReentrantLock();
public 返回值 run(){
l.lock();
.....;
l.unlock;
}
公平锁与不公平锁:以上三种都是不公平锁,所谓公平锁就是,在等待之前线程执行完的时候,谁先开始等待谁先拿到锁的对象,前三个都是对锁进行争抢。
当fair为true时,就是公平锁 :Lock l = new ReentrantLock(fair:true);
线程死锁:两个线程都在等待对方先执行完,而导致程序死锁在那里。
4.WAITING: 线程无限期等待另一个线程执行特定操作的状态。
生产者与消费者问题:我会另一写一篇博客,
5.TIMED_WAITING: 线程正在等待另一个线程执行最多等待时间的操作的状态。
6.TERMINATED:线程已退出的状态。
线程的中断:interrupt()一个线程是一个独立的执行路径,他是否应该结束,应该有其自身决定,一个线程开始执行的时候,他一定会涉及很多资源,也会有很多需要释放的资源,如果直接从外部关闭,会导致很多资源来不及释放,而一直占用而
导致产生很多垃圾。我们可以通过给线程打标记的方式,去通知线程关闭,这里就需要用到interrupt方法,当线程接收到标记后,new一个InterruptedException异常,然后进入catch块,然后由程序员觉得是否让其死亡,如
果需要线程中断,直接return结束这个方法。