其他分享
首页 > 其他分享> > M10. 阻塞队列 线程池

M10. 阻塞队列 线程池

作者:互联网

█ 7.阻塞队列

阻塞队列空,取阻塞;;阻塞队列满,插阻塞

好处:不得不阻塞,商家欢迎阻塞。

BlockingQueue<String> queue = new ArrayBlockingQueue<>(capacity3);


7.1 阻塞队列的种类:

ArrayBlockingQueue有界 // LinkedBlockingQueue 无界// SynchronousQueue 单个元素无容量 put() take() 不消费不生产// LinkedBlockingDeque双向阻塞队列

○ 7.2 阻塞队列用在哪:

1.生产者消费者模式 //2.线程池// 3.消息中间件
多线程的判断 用while 不能用if<2个线程>,线程多了会出错。 防止虚假唤醒

○ ○ 7.2.1 生产者消费者模式

lock.newCondition(); condition.await(); condition.signalAll();精确唤醒condition.signal(); finally{condition.unlock();}


█ 8.线程 进程

Linux 系统中单个进程的最大线程数有其最大的限制 PTHREAD_THREADS_MAX。 1024<root是unlimited>
线程的 stack 所占用的内存,用 ulimit -s 可以查看默认的线程栈大小,一般情况下,这个值是8M=8192KB。

进程是资源分配的基本单位;线程是系统调用(cpui调度)的基本单位。

开发人员写的程序是 进程,进程是一系列线程和资源的统称,一个进程至少1个线程main,还可以new Thread 创建别的线程;;;

多线程:可以同时进行 调用共享变量 并发操作。

线程共享的环境 包括 1.进程代码段,2.进程的公有数据(利用这些共享的数据,线程间通信),3.堆中的数据、4.进程打开的文件描述符、5.进程ID和进程组ID。



○ 8.1 进线程区别

1、地址空间:同一进程的线程共享本进程的地址空间,而进程之间则是独立的地址空间。

2、资源拥有:同一进程内的线程共享本进程的资源,但是进程之间的资源是独立的。

3、一个进程崩溃后,在保护模式下不会对其他进程产生影响,但是一个线程崩溃整个进程都死掉。所以多进程要比多线程健壮。

4、进程切换时,消耗的资源大,效率高。频繁的切换时,线程好:要求同时进行并且又要共享某些变量的并发操作,只能用线程,不能用进程。

5、执行过程:每个独立的进程程有一个程序运行的入口、顺序执行序列和程序入口。但是线程不能独立执行,必须依存在应用程序中,由应用程序提供多个线程执行控制。

6、线程是处理器调度的基本单位,但是进程不是。

7、两者均可并发执行。



○ 8.2 进线程 优缺点:

线程执行开销小,但是不利于资源的管理和保护。线程适合在SMP机器(双CPU系统)上运行。

进程执行开销大,但是能够很好的进行资源管理和保护。进程可以跨机器前移。



○ 8.3 用到多线程 的场景

1.下载文件 操作文件 /// 2.后台线程 /// 3.分布式 /// 4.备份日志



○ 8.4 多线程 实现方法 callable

1.继承Thread类 // 2.Runnable接口无返回值不抛异常 // 3.callable有返回值抛异常 // 4.线程池

implements Runnable run()

implements Callable<Integer>  call()

FutureTask<Integer> futureTask = new FutureTask<>(new MyThread());
while(!futureTask.isDone()){}
futureTask.get(); callable线程如果没有计算完,会堵塞,。公用的futureTask只计算一次。

多线程 实现同步方法

同步的实现方面有两种,分别是synchronized,wait与notify

wait():使一个线程处于等待状态,并且释放所持有的对象的lock。

sleep():使一个正在运行的线程处于睡眠状态,是一个静态方法,调用此方法要捕捉InterruptedException异常。

notify():唤醒一个处于等待状态的线程,注意的是在调用此方法的时候,并不能确切的唤醒某一个等待状态的线程,而是由JVM确定唤醒哪个线程,而且不是按优先级。

Allnotity():唤醒所有处入等待状态的线程,注意并不是给所有唤醒线程一个对象的锁,而是让它们竞争。

?????????○ 8.5 定位有问题的线程可以用如下命令

ps -mp pid -o THREAD,tid,time | more

2、查看JAVA进程的每个线程的CPU占用率

ps -Lp 5798 cu | more # 5798是查出来进程PID

3、追踪线程,查看负载过高的原因,使用JDK下的一个工具

jstack 5798                        # 5798是PID

jstack -J-d64 -m 5798       # -j-d64指定64为系统

jstack 查出来的线程ID是16进制,可以把输出追加到文件,导出用记事本打开,再根据系统中的线程ID去搜索查看该ID的线程运行内容,可以和开发一起排查。


█ 9.线程池 ThreadPoolExecutor 要自定义

线程池特点:线程复用 ;控制最并发数 ; 管理线程。
线程池控制运行线程的数量,将任务放入队列。


优点: 1.降低资源消耗(创建销毁的) 2.提高相应速度(不要等创建) 3.提高线程的可管理性(统一分配 调用)


线程池通过Executor框架实现,用到了Executors ExecutorService,ThreadPoolExecutor这几个类

○ 9.1 线程池种类:

有5种线程池:Executors.newFixedThreadPool(int)一池固定数 // Executors.newSingleThreadExecutor()一池一个 // Executors.newCachedThreadPool()一池多线程

这几个请求队列都是Integer.MAX_VALUE OOM

○ 9.2 底层 线程池自定义

7大参数

流程:

corePoolSize 不满,直接执行,,如果大于 放入队列;队列满了 maximunPoolsize开启;队列又满了,拒绝策略

○ 9.3 线程池拒绝策略

○ 9.4 合理配置线程池

先查CPU核数 System.out.println(Runtime.getRuntime().availableProcessors());
两种:
1.CPU密集型 < cpu核数+1 个线程 >
2.IO密集型 < cpu核数*2,因为有大量阻塞 还有一种 cpu核数/(1-阻塞系数0.8-0.9)>

█ 函数看CPU核数//内存

查看CPU的核数:System.out.println(Runtime.getRuntime().availableProcessors());
查看java虚拟机中的内存总量: Runtime.getRuntime().totalMemory();
虚拟机试图使用的最大内存量: Runtime.getRuntime().maxMemory();

█ 2 . CPU比较高的原因

1、首先查看是哪些进程的CPU占用率最高(如下可以看到详细的路径)

ps -aux --sort -pcpu | more

█ ?????????○ 8.5 定位有问题的线程可以用如下命令

ps -mp pid -o THREAD,tid,time | more

2、查看JAVA进程的每个线程的CPU占用率

ps -Lp 5798 cu | more # 5798是查出来进程PID

3、追踪线程,查看负载过高的原因,使用JDK下的一个工具

jstack 5798                        # 5798是PID

jstack -J-d64 -m 5798       # -j-d64指定64为系统

jstack 查出来的线程ID是16进制,可以把输出追加到文件,导出用记事本打开,再根据系统中的线程ID去搜索查看该ID的线程运行内容,可以和开发一起排查。

█ 1. 提高并发性

1、提高CPU并发计算能力

(1)多进程&多线程

(2)减少进程切换,使用线程,考虑进程绑定CPU

(3)减少使用不必要的锁,考虑无锁编程

(4)考虑进程优先级

(5)关注系统负载

2、改进I/O模型

(1)DMA技术

(2)异步I/O

(3)改进多路I/O就绪通知策略,epoll

(4)Sendfile

(5)内存映射

(6)直接I/O

标签:队列,阻塞,M10,线程,进程,CPU,5798
来源: https://www.cnblogs.com/ming-michelle/p/14657118.html