41.sleep() 和 wait() 有什么区别?
sleep()是Thread类中的方法,wait()是Object类中的方法。
sleep()不释放锁,wait()释放锁。
sleep()在任何地方都能使用,而wait()只能在同步方法或代码块中使用。
sleep()在设置的时间过后会重新竞争资源,而wait()必须由notify()或notifyAll()方法来释放。
42.notify()和 notifyAll()有什么区别?
notify和notifyAll都是用来唤醒被wait方法执行的线程。
notify是唤醒当前共享资源上随机一个被wait()的线程。
notifyAll是唤醒当前共享资源上所有被wait()的线程.
43.线程的 run()和 start()有什么区别?
run()方法是执行线程体中的代码,start()是启动线程
正常的顺序是用start()启动线程,每一个线程抢占到CPU之后执行run()方法,这样才有多线程的效果。
如果直接执行run()方法就相当于直接将一个线程执行,这就相当于单线程执行。
44.创建线程池有哪几种方式?
ThreadPoolExecutor():最原始的线程池创建。
newFixedThreadPool(int nThreads):固定线程数的线程池。适用于负载比较重的服务器。
newCachedThreadPool():按照需要创建新线程的线程池。该线程池可以无限扩展,当需求增加时,可以添加新的线程,而当需求降低时会自动回收空闲线程,适用于执行很多的短期异步操作,或者是负载较轻的服务器。
newSingleThreadExecutor():只有一个线程的线程池。适用于需要保证顺序执行各个任务的场景。
45.线程池都有哪些状态?
线程池有五种状态,它是在ThreadPoolExecutor类中定义的常量
RUNNING:创建线程池之后的初始状态,这种状态下可以执行任务。
SHUTDOWN:该状态下线程池不会再接收新任务,但是会将工作队列中的任务执行完毕。
STOP:该状态下线程池不会再接收新任务的同时也不会处理工作队列中的剩余任务,并且会中断所有工作线程。
TIDYING:该状态下所有任务都已终止或者处理完成,将会执行terminated()钩子方法。
TERMINATED:执行完terminated()钩子方法之后的状态,terminated钩子方法是在Executor终止时调用,默认实现不执行操作。
线程池的状态转换规则:
线程池创建之后状态为RUNNING;
RUNNING状态下,执行shutdown()方法,会使线程池由RUNNING状态转为SHUTDOWN状态;
RUNNING状态下,执行shutdownNow()方法,会使线程池由RUNNING状态转为STOP状态;
SHUTDOWN状态下,执行shutdownNow()方法,会使线程池由SHUTDOWN状态转为STOP状态;
等待线程池中的任务线程停止,工作队列清空之后,会使线程池由STOP状态转为TIDYING状态;
执行完terminated()钩子方法之后,会使线程池由TIDYING状态转为TERMINATED状态。
46.线程池中 submit()和 execute()方法有什么区别?
execute()方法位于接口Executor中,而submit()方法位于AbstractExecutorService中。
execute()的参数只可以使Runnable类型,而submit()重载了三个方法,参数可以是Runnable类型,也可以是Callable类型,也可以是Runnable+结果。
execute()方法没有返回值,而submit()方法有返回值。
submit()底层是调用execute()方法。
47.在 java 程序中怎么保证多线程的运行安全?
线程的安全问题体现在三个方面:
线程切换导致的原子性问题:要不都执行要不都不执行。JDK Atomic开头的原子类、synchronized、LOCK可以解决。
缓存导致的可见性问题:一个线程对共享变量的修改,其他线程能够立即看到。synchronized、LOCK、volatile可以解决。
编译优化导致的有序性问题:程序执行顺序按照代码的先后顺序执行。volatile可以解决。
48.多线程锁的升级原理是什么?
没有优化锁之前,synchronized是重量级锁(悲观锁),使用wait和notify或notifyAll来切换线程状态,非常耗费资源影响性能,所以在JDK6对synchronized关键字进行优化,从锁级别从低到高分为:无锁、偏向锁、轻量级锁、重量级锁。锁升级是不可逆的。