一、线程的生命周期:
新建、就绪、运行、阻塞、死亡。如下图所示:
二、线程安全的出现和解决:
1.出现的原因:当一个线程操作某一个共享资源的时候,该操作尚未完成,其它线程参与进来,也去操作执行该资源,就会引发线程的安全问题。
2.解决办法:当一个线程操作的时候,其他线程不能参与进来,知道该线程操作完后,其他线程才能进行操作,这种情况即使是线程出现了阻塞,也不会被改变。
3.在java中,通过同步机制,来解决线程的安全问题。
方式一:同步代码块
sychronized(同步监视器){ //需要被同步的代码 }
说明:操作共享数据的代码,就是需要被同步的代码
共享数据:多个线程共同操作的变量。
同步监视器:俗称:锁。任何一个类的对象,都可以充当锁。多个线程必须共用一把锁才能线程安全。
同步解决了线程的安全,但是同时只能有一个线程参与,其他等待,相当于一个单线程,效率低。
方式二:同步方法:
如果操作共享数据的代码完整的声明在一个方法中,这就是同步方法。
private sychronized void show(){//同步监视器:this //需要被同步的代码 } public void run(){ show();//调用线程安全的同步方法 }
注意:以上是在接口实现多线程的代码,在继承实现多线程的时候,this不是一个共有的,不能充当锁。这个时候就要加上静态或者用类来充当锁:
private static sychronized void show(){//同步监视器:this //需要被同步的代码 }
三、死锁和解决:
1.死锁:不同线程分别占用对方需要的同步资源不放弃,都在等待对方放弃自己需要的同步资源,就形成了线程的死锁。
出现死锁后,不会出现异常,不会有提示,只是所有的线程都处于阻塞状态,无法继续。
2.解决线程安全问题的方式三:lock锁——JDK5.0新增
private ReentrantLock lock = new ReentrantLock ();//实例化ReentrantLock lock.lock();//在需要同步的代码之前调用 lock.unlock();//同步结束后解除
3.synchronized和lock的异同?
相同:都是用来解决线程的安全问题
不同:sychronized机制在执行完相应的同步代码以后,自动的释放同步监视器,lock需要手动启动,同时结束同步后也需要手动实现。而且lock只有代码块锁,synchronize有代码块锁和方法锁。
四、线程的通信:
涉及到的三个方法:
1. wait():一旦执行此方法,当前线程就进入阻塞状态,并释放同步监视器。
notify():一旦执行此方法,就会唤醒被wait的一个线程。如果有多个线程被wait,就唤醒优先级高的。
notifyAll():一旦执行此方法,就会唤醒所有被wait的线程。
2.注意:这三个方法必须使用在同步代码块或同步方法中。
这三个方法的调用者必须是同步代码块或同步方法中的同步监视器。否则会出现IllegalMonitorStateException异常。
3.sleep()和wait()异同?
相同:都可以使得当前线程进入阻塞状态。
不同:①声明位置不同:Thread类中声明的sleep(),Object类中声明的wait()
②调用的要求不同:sleep()可以在任何需要的场景下调用。wait()必须在同步代码块或同步方法中。
③关于是否释放同步监视器:如果两个方法都使用在同步代码块或同步方法中,sleep()不会释放锁,wait()会释放锁。