线程死锁问题

有如下两个问题:
第一:线程死锁后CPU和内存的状况如何?
答:内存使用量不变,因为死锁后双方线程除了占用到自己的资源以外,并没有申请到其他内存资源。CPU应该分为两种情况:第一,在申请不到资源时一直处于等待,则会占用CPU的资源,导致CPU使用增加。第二:如果申请不到CPU资源时,就进入休眠状态,退出等待队列,就不会占用CPU资源。
用户级线程与内核线程有三种对应情况:多对一,一对一,多对多。在多对一情况下,即多个线程只分配了一个内核线程,所以只要有一个线程阻塞,则整个进程也会阻塞。在一对一和多对多的情况下,一个线程阻塞,cpu还可以调度其他线程资源到内核线程,所以并不会造成进程阻塞。
第二:发生死锁以后,如何快速定位死锁线程,已经如何解决死锁?
答:发生死锁以后,如果是主线程和其他工作线程发生死锁,则程序会停止响应,若是其他线程之间发生死锁,则相关程序不能运行。在编码时,对线程添加日志,记录各个线程的堆栈信息(有相应的函数可以直接获取线程的堆栈信息),如果发生死锁,可以查看日志以便查找死锁原因。然后修改冲突的代码。最好的办法就是在编码时,对多线程之间的共享资源进行加锁,以便互斥访问。多个线程直接使用资源时,最好采用统一顺序对共享资源进行枷锁。且使用对共享资源的超时限制。
第三:直接杀死线程好吗?
不行,如果直接杀死线程,会导致线程锁占用的资源也会被回收,其他线程则不能再利用此资源。最好的办法就是对占用共享资源的线程设置超时限制,如果占用资源超时,则自动释放此资源。
第四:线程池?
线程池的主要作用就是缩短线程的创建和销毁时间。假设一个服务器一天要处理10000个请求,并且每个请求需要一个单独的线程完成。在线程池中,线程数一般是固定的,所以产生线程总数不会超过线程池中线程的数目,而如果服务器不利用线程池来处理这些请求则线程总数为10000.但如果使用线程池,只需要在初始化时指定要创建的线程数量,并将之启动,以后在执行过程中都不需要创建新的线程,只需要将请求加入到任务队列中,用已经启动的线程去工作就好。待任务队列中的所有任务都执行完以后,就返回线程池中再等待任务的到来。这样就只执行了一次创建线程,一次销毁线程。提升效率。主要运用在服务器端,因为服务器有时候就是每接收一个监听,他就需要一个线程来处理该客户端的请求,线程池是最好的办法。注意,线程池这个类是可以自己写并实现的,需要一个创建线程方法,添加任务队列方法,取出并执行队列中任务的方法,以及销毁方法这四个核心方法。

线程池中线程个数的确定:
调整线程池的大小基本上就是避免两类错误:线程太少或线程太多。幸运的是,对于大多数应用程序来说,太多和太少之间的余地相当宽。
请回忆:在应用程序中使用线程有两个主要优点,尽管在等待诸如 I/O 的慢操作,但允许继续进行处理,并且可以利用多处理器。在运行于具有 N 个处理器机器上的计算限制的应用程序中,在线程数目接近 N 时添加额外的线程可能会改善总处理能力,而在线程数目超过 N 时添加额外的线程将不起作用。事实上,太多的线程甚至会降低性能,因为它会导致额外的环境切换开销。
线程池的最佳大小取决于可用处理器的数目以及工作队列中的任务的性质。若在一个具有 N 个处理器的系统上只有一个工作队列,其中全部是计算性质的任务,在线程池具有 N 或 N+1 个线程时一般会获得最大的 CPU 利用率。
对于那些可能需要等待 I/O 完成的任务(例如,从套接字读取 HTTP 请求的任务),需要让池的大小超过可用处理器的数目,因为并不是所有线程都一直在工作。通过使用概要分析,您可以估计某个典型请求的等待时间(WT)与服务时间(ST)之间的比例。如果我们将这一比例称之为 WT/ST,那么对于一个具有 N 个处理器的系统,需要设置大约 N*(1+WT/ST) 个线程来保持处理器得到充分利用。

你可能感兴趣的:(面试缺陷)