本次整理的内容以下:java
进程是一个可执行的程序,是系统资源分配的基本单位;线程是进程内相对独立的可执行单元,是操做系统进行任务调度的基本单位。算法
因为每一个进程都有独立的内存空间,进程之间的数据交换须要经过操做系统内核。须要在操做系统内核中开辟一块缓冲区,进程 A 将须要将数据拷贝到缓冲区中,进程 B 从缓冲区中读取数据。由于共享内存没有互斥访问的功能,需配合信号量进行互斥访问。编程
管道的实现方式:小程序
管道的特色:
只容许具备血缘关系的进程间通信,只容许单向通信,进程在管道在,进程消失管道消失。管道内部经过环形队列实现。
有名管道(命名管道):
经过文件的方式实现进程间的通讯。容许无血缘关系的进程间的通讯数组
由消息组成的链表,存在系统内核中。克服了信号量传递的信息少,管道只能承载无格式的字符流及缓冲区的大小受限等特色。经过消息类型区分消息。服务器
本质是一个计数器,不以传送数据为目的,主要用来保护共享资源,使得资源在一个时刻只有一个进程独享。多线程
可用于不一样机器间进程的通讯。
套接字包括 3 个属性:域、类型、 协议。并发
建立 socket 经过 bind 命名绑定端口,listen 建立队列保存未处理的客户端请求,accept 等待客户端的链接,connect 服务端链接客户端 socket,close 关闭服务端客户端的链接。异步
stream 和 datagram 的区别:
stream 能提供有序的、可靠的、双向的、基于链接的字节流(TCP),会有拆包粘包问题。
datagram 是无链接、不可靠、使用固定大小的缓冲区的数据报服务(UDP),由于基于数据报,且有固定的大小,因此不会有拆包粘包问题。socket
详细请参考:进程间的五种通讯方式介绍
共享内存:
Java 采用的就是共享内存,内存共享方式必须经过锁或者 CAS 技术来获取或者修改共享的变量,看起来比较简单,可是锁的使用难度比较大,业务复杂的话还有可能发生死锁。
消息传递:
Actor 模型便是一个异步的、非阻塞的消息传递机制。Akka 是对于 Java 的 Actor 模型库,用于构建高并发、分布式、可容错、事件驱动的基于 JVM 的应用。消息传递方式就是显示的经过发送消息来进行线程间通讯,对于大型复杂的系统,可能优点更足。
详细请参考:Java 内存模型分析
优势:
充分利用 cpu 的资源,提升 cpu 的使用率,使程序的运行效率提升。
缺点:
有大量的线程会影响性能,操做系统会在线程之间切换,会增长内存的开销。可能会产生死锁、存在线程之间的并发问题。
详细请参考:并发编程挑战:死锁与上下文切换
详细请参考:【SharingObjects】ThreadLocal
java.lang.ThreadLocal.ThreadLocalMap.Entry:
static class Entry extends WeakReference<ThreadLocal<?>> { /** The value associated with this ThreadLocal. */ Object value; Entry(ThreadLocal<?> k, Object v) { //重点!!!!! super(k); value = v; } }
由于 ThreadLocalMap 中的 key 是弱引用,而 key 指向的对象是 threadLocal,一旦把 threadLocal 实例置为 null 以后,没有任何强引用的对象指向 threadLocal 对象,所以 threadLocal 对象会被 Gc 回收,但与之关联的 value 却不能被回收,只有当前线程结束后,对应的 map value 才会被回收。若是当前线程没结束,可能会致使内存泄漏。
如线程池的场景,在线程中将 threadlocal 置为 null,但线程没被销毁且一直不被使用,就可能会致使内存泄漏
在调用 get、set、remove 方法时,会清除线程 map 中全部 key 为 null 的 value。因此在不使用 threadLocal 时调用 remove 移除对应的对象。
ThreadPoolExecutor 继承关系图:
shutDown 方法执行以后会变成 SHUTDOWN 状态,没法接受新任务,随后等待已提交的任务执行完成。
shutDownNow 方法执行以后变成 STOP 状态,没法接受新任务。并对执行中的线程执行 Thread.interrupt()方法。
当任务来时,若是当前的线程数到达核心线程数,会将任务加入阻塞队列中,若是阻塞队列满了以后,会继续建立线程直到线程数量达到最大线程数,若是线程数量已经达到最大线程数量,且任务队列满了以后,会执行拒绝策略。
若是想让核心线程被回收,可使用 allowCoreThreadTimeOut 参数,若是为 false(默认值),核心线程即便在空闲时也保持活动状态。若是 true,核心线程使用 keepAliveTime 来超时等待工做。
java.util.concurrent.Executors 类:
public static ExecutorService newFixedThreadPool(int nThreads) { return new ThreadPoolExecutor(nThreads, nThreads, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<Runnable>()); }
生成一个固定大小的线程池,此时核心线程数和最大线程数相等,keepAliveTime = 0 ,任务队列采起 LinkedBlockingQueue 无界队列(也可设置为有界队列)。
适用于为了知足资源管理需求,而须要限制当前线程数量的应用场景,好比负载比较重的服务器。
public static ExecutorService newSingleThreadExecutor() { return new FinalizableDelegatedExecutorService (new ThreadPoolExecutor(1, 1, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<Runnable>()));
生成只有一个线程的线程池,核心线程数与最大线程数都是 1,keepAliveTime = 0,任务队列采起 LinkedBlockingQueue,适用于须要保证顺序地执行各个任务,而且在任意时间点不会有多个线程是活动的应用场景。
public static ExecutorService newCachedThreadPool() { return new ThreadPoolExecutor(0, Integer.MAX_VALUE, 60L, TimeUnit.SECONDS, new SynchronousQueue<Runnable>()); }
核心线程数是 0,最大线程数是 int 最大值,keepaliveTime 为 60 秒,任务队列采起 SynchronousQueue,适用于执行不少的短时间异步任务的小程序,或者是负载较轻的服务器。
public static ScheduledExecutorService newSingleThreadScheduledExecutor() { return new DelegatedScheduledExecutorService (new ScheduledThreadPoolExecutor(1)); } public ScheduledThreadPoolExecutor(int corePoolSize) { super(corePoolSize, Integer.MAX_VALUE, 0, NANOSECONDS, new DelayedWorkQueue()); }
定长的线程池,支持周期性任务,最大线程数是 int 最大值,超时时间为 0,任务队列使用 DelayedWorkQueue,适用于须要多个后台执行周期任务,同时为了知足资源管理需求而须要限制后台线程的数量的应用场景。
任务执行失败后,只会影响到当前执行任务的线程,对于整个线程池是没有影响的。
详细请参考:ThreadPoolExecutor 线程池任务执行失败的时候会怎样
kill -9 pid 操做系统内核级别强行杀死某个进程。
kill -15 pid 发送一个通知,告知应用主动关闭。
ApplicationContext 接受到通知以后,会执行 DisposableBean 中的 destroy 方法。
通常咱们在 destroy 方法中作一些善后逻辑。
调用 shutdown 方法,进行关闭。