1.进程与线程的区别
1.进程是一个执行中的程序,是系统进行资源分配和调度的一个独立单位
2.线程是进程的一个实体,一个进程中一般拥有多个线程。线程之间共享地址空间和其他资源(所以通信和同步等操作,线程比进程更加容易)
3.线程一般不拥有系统资源,但是也有一些必不可少的资源(使用ThreadLocal存储、线程级别的缓存?)
4.线程上下文切换比进程上下文切换要快很多
5.线程上下文切换比进程上下文切换要快很多的原因:
1.进程切换时,涉及到当前进程的CPU环境的保存和新被调度运行的CPU环境的设置
2.线程切换时,仅需要保存和设置少量的寄存器内容,不涉及存储管理方面的操作
3.线程可以拥有独属于自己的资源吗?可以。通过threadlocal可以存储线程的特有对象,也就是属于当前线程的资源。
2.进程之间常见的通信方式
1.通过使用套接字socket来实现不同机器之间的进程通信
2.通过映射一段可以被多个进程访问的共享内存来通信
3.通过写进程和读进程利用管道进行通信
3.多线程与单线程的关系
1.多线程是指在一个进程中,并发执行了多个线程,每个线程都实现了不同的功能
2.在单核CPU中,将CPU分为很小的时间片,在每一时刻只能有一个线程在执行,是一种微观上轮流占有CPU的机制。由于CPU轮询的速度非常快,所以看起来像是同时在执行一样。
3.多线程会存线程上下文切换,会导致程序执行速度变慢
4.多线程不会提高程序的执行速度,反而会降低速度。但是对用户来说,可以减少用户的等待响应时间,提高了资源的利用效率。
解析:
搞清楚多线程和单线程之间的区别,有助于我们理解为什么要使用多线程并发编程。多线程并发利用了CPU轮训时间片的特点,在一个线程进入阻塞状态时,可以快速切换到其余线程执行其余的操作,这有利于提高资源的利用率,最大限度的利用系统提供的处理能力,有效减少了用户的等待响应时间。
但是多线程并发编程也会带来数据的安全问题,线程之间竞争也会导致线程思索和锁死等活性故障。线程之间的上下文切换也会带来额外的开销。
4.线程的状态
1.new
2.runnable
3.blocked
4.waiting
5.time_waiting
6.terminated
new:创建一个线程,但是还没有调用start方法启动的线程所处的状态
runnable: 包含2种状态:正在运行或者正在等待CPU资源,总体来说就是当我们创建线程并启动之后,就属于runnable状态。
blocked:阻塞状态,当线程准备进入synchronize同步代码块或者同步方法的时候,需要申请一个监视器锁而进行的等待,会使线程进入blocked状态。
waiting:该状态的出现是因为调用了object.wait()或者thread.join()或者locksupport.park()。处于该状态下的线程在等待另一个线程执行一些其余action来将其唤醒。
timed_waiting: 与上面状态是一样的,不过等待的时间是明确的。
terminated: 消亡状态,线程执行结束了,run方法执行结束表示线程处于消亡状态了。
sleep和wait的区别:
sleep方法:是Thread类的静态方法,当前线程将睡眠n毫秒,线程进入阻塞状态。当睡眠时间到了,会解除阻塞,进入可运行状态,等待CPU的到来。睡眠不释放锁(如果有的话)
wait方法:是object的方法,必须与synchronize关键字一起使用,线程进入阻塞状态,当notify或者notifyall被调用后,会解除阻塞状态。但是,只有重新占有互斥锁之后才会进入可运行状态。睡眠时,会释放互斥锁。
join方法:当前线程调用,则其他线程全部停止,等待当前线程执行完毕,接着执行。
yield方法: 该方法使得线程放弃当前分得的CPU时间。但是不使线程阻塞,即线程仍处于可执行状态,随时可能再次分得CPU时间。
5.线程活性故障有哪些
由于资源的稀缺性或者程序自身的问题导致线程一直处于非runnable状态,并且其处理的任务一直无法完成的现象被称为是线程活性故障。
常见的线程活性故障包括 死锁,锁死,活锁与线程饥饿。
每一个线程都有其特定的任务处理逻辑。由于资源的稀缺性或者资源本身的一些特性,导致多个线程需要共享一些排他资源,比如说处理器,数据库连接等。当出现资源争用的时候,部分线程会进入等待状态。
线程死锁:
死锁是最常见的一种线程活性故障。死锁的起因是多个线程之间相互等待对方而被永远暂停(处于非runnable)。死锁的产生必须满足如下四个必要条件:
1.资源互斥:一个资源每次只能被一个线程使用
2.请求保持条件:一个线程因为请求资源而阻塞时,对已获得的资源保持不放
3.不剥夺条件:线程已经获得的资源,在未使用完之前,不能强行剥夺
4.循环等待条件:若干线程之间形成一种头尾相接的循环等待资源关系
如何避免死锁:
粗锁法:使用一个粗粒度的锁来消除请求保持条件
锁排序:指定获得取锁的顺序,比如某个线程只有获得A锁和B锁,才能对资源进行操作,在多线程条件下,只有先获得A锁的线程才有资格获得B锁,按顺序获取锁就可以避免死锁,
线程锁死:
等待线程由于唤醒其所需的条件永远无法成立,或者其他线程无法唤醒这个线程而一直处于非运行状态(线程并未终止)导致其任务一直无法展开。
活锁:
活锁是一种特殊的线程活性故障。当一个线程一直处于运行状态,但是其所执行的任务却没有任何进展称为活锁。比如一个线程一直在申请其所需要的资源,但是却无法申请成功。
线程饥饿:
指线程一直无法获得所需要的资源导致任务一直无法运行的情况。线程调度模式有公平模式和非公平模式。线程非公平模式下,会发生线程饥饿。
线程饥饿发生时,如果线程处于可运行状态,也就是其一直在申请资源,那么就会转变为活锁
只要存在一个或多个线程因为获取不到其所需要的资源而无法进展就是线程饥饿,所以线程死锁其实也算是线程饥饿。