创建线程的方式:1)、实现Runnable接口 2)、继承Thread类
守护线程:守护线程运行再程序后台。当主线程结束的时候,不管守护线程有没有执行完,守护线程都会结束,并不会影响虚拟机的退出。
什么样的线程是守护线程?
当线程对象A调用setDaemon()方法设置为true时,该线程即为守护线程。即。A.setDaemon(true)。A就会标记为守护线程
优先级别:线程得最大优先级别为10,最小优先级别是1,默认优先级别为5。优先级别高得线程获取cpu资源得机率比低优先级别得线程要高。并不是说高优先得线性一定要比低优先级线程先执行。这个开始理解得时候我就搞混淆了。
setPriority()方法:设置线程的优先级别。范围为1~10
getPriotity()方法:获取线程的优先级别
sleep()方法。当线程调用sleep()方法后,线程会从运行状态变为阻塞状态,当过了睡眠时间后,线程会从阻塞状态变为可运行状态。需要注意的地方是,当线程获得锁后,调用sleep()方法,线程并不会释放锁资源。
yield()方法。当线程调用yield()方法后,线程会从运行状态变为就绪状态,即线程获取到cpu资源,进入就绪状态,重新和其他线程争夺cpu资源的的使用权。注意点:线程让出cpu资源后,该线程也可立即获取cpu资源继续执行,并不是需要其他线程运行后,它才能获取到cpu资源继续运行。该方法只是提高了其他线程获取cpu资源的机率。
join()方法。在线程A中调用线程B的join()方法,线程A会进入阻塞状态,直到线程B执行完之后,线程A才会从阻塞状态变为就绪状态
interrupt()方法/isInterrupt()方法
java中的线程中断是一种线程的协作模式,通过设置线程的中断标志并不能直接终止该线程,而是被中断的线程根据中断状态自行处理。
interrupt()方法:中断线程,只是设置一个线程标识,并不能中断线程的执行。例如:运行线程A时。在线程B中调用线程A的interrupt()方法来设置线程A的中断标识为true。线程A实际上并没有中断,还会继续执行。
注:当线程调用wait()、sleep()和join()方法,线程进入阻塞状态后,再使用interrupt()方法,会抛出java.lang.InterruptedException异常。
isInterrupted()方法:检验线程是否中断,如果是返回true,否则返回false。即线程调用了interrupt()方法,返回true,否则返回false
这两个方法配合使用,可以使线程优雅的退出
优雅的退出线程的另一种方式:通过设置一个标识符,再适当的时机改变标识符的值。通过标识符值得改变而退出线程
wait()/notify()/notifyAll()方法:
wait()方法:线程调用wait()方法,线程将进入阻塞状态,但与sleep()方法不同的时,调用wait方法会释放锁资源。当调用notify()方法或者notifyAll()方法后,线程会从阻塞状态转换可运行状态。
notity()方法/notifyAll()方法: 唤醒等待中的线程,
经典场景:生产-消费者模式
模拟场景:一个餐馆,由一个厨师和一个服务员,接到订单后,服务员需等到厨师做好食物,厨师准备好食物后,会通知服务员取走食物。然后继续等待。厨师代表生产者,服务员代表消费者
疑问:这个场景中的共享资源为服务员?使用服务员作为排它锁
死锁:是指两个或者两个以上的线程在执行过程中,因为争夺资源而造成的互相等待的现象,在无外力的情况下,这些线程会一直相互等待而无法继续运行下去(摘自《Java并发编程之美》)
死锁:某个任务在等待另一个任务,而后者又等待别的任务,这样一直下去,直到链条上的任务又在等待第一个任务释放锁,这得到了一个任务之间相互等待的连续循环,没有哪个线程能继续,被称之为死锁(摘自《Java编程思想》)
产生死锁的四个必备条件:
1、互斥条件:线程使用的资源中至少有一个不能共享
2、线程持有资源并等待另一个资源
3、资源不能被抢占:指线程获取到的资源在自己使用完之前不能被其他资源抢占,只有在自己使用完之后才有自己释放资源
4、循环等待资源,一直不退出
如何避免死锁?
要发生死锁的化,必须满足上面四个条件,所以 要防止死锁,破坏上述四个条件中的一个即可
经典死锁案例。哲学家用餐,哲学家围成一圈吃饭。哲学家很穷,买不起足够多的筷子,每个人左手边和右手边都有一只筷子,也就是多少哲学家就由多少只筷子,哲学家必须得到左手边和右手边的筷子才能就餐。如果哲学家左边和右边的人都在用筷子,则必须等待,直到有筷子可用
参考:《java编程思想》
《java并发编程之美》
肖海鹏老师的教学视频
之后会有博客对上述的一些知识点使用代码实现,