长沙设备建站按效果付费,北京培训学校,手机哪个网站好,wordpress会员中心404并发#xff1a;多个线程#xff08;进程#xff09;竞争一个资源
并行#xff1a;多个线程#xff08;进程#xff09;同时运行不同资源
线程和进程的关系简单地说#xff0c;进程是一个容器#xff0c;一个进程中可以容纳若干个线程#xff0c;一个进程里面#…并发多个线程进程竞争一个资源
并行多个线程进程同时运行不同资源
线程和进程的关系简单地说进程是一个容器一个进程中可以容纳若干个线程一个进程里面至少有一个线程
跨系统的并发实现底层原理需要更好的机器来实现不是跨系统的就是调用**操作系统的CAH**来实现如下图所示
线程的状态
- 新建--就绪--运行--阻塞--等待---死亡 - 就绪队列、阻塞队列、等待队列
- 一个线程申请资源时无法让其马上执行而是先进入队列变为就绪态然后等待资源分配若马上就让其直接执行会导致之前正在执行的进程中断、丢失
- 和操作人员交互多的指令在运行时优先级越高、响应也越迅速
- 每个进程在CPU中分配的时间片是不同的当该进程的时间片用完且该进程还没完成时就会中心进入就绪态等待下一次执行直到完成为止同时若一个进程在分配的时间还没用完就已经完成此时CPU会马上切换任务不会休息比如进程A共需要5ms但是cpu分配了10此时在执行到5ms时CPU便不再处理A转而执行B另外只有没有任何进程时CPU才会休息
- 不同的系统每次为进程分配的时间片方式不同一般是随机的也有等长的比如linux
- 在操作系统中每个进程是否可以进入就绪、运行是靠优先级决定的具体如何计算优先级每个系统的方法可能不一样主要方法有优先级队列、等待响应比等
- 当一个进程的时间片用完操作系统会记录此时的状态即执行到哪里也就是执行到的地址和下一次执行时间以便下一轮时间片到的时候可以继续执行
- 操作系统选中哪个线程去执行是不确定的是随机的
- 进程执行完后进入死亡状态时间片用完重新回到就绪态
- 阻塞队列竞争枷锁资源失败的时候进程A就会进入阻塞队列若某一刻被竞争的资源被正在占用的进程B释放此时A又可以进去就绪队列竞争资源
- 等待队列一个处于等待队列的进程A是不会自己接触等待状态的只有当别人唤醒时他才能进入就绪态去竞争资源同时一个进程可以自己进入等待队列正在执行的进程也可以自己进入等待队列
- 先进入就绪态的被先执行的概率越大但不是百分之百后进入就绪态的可能比先进入的更早执行
- 在线程完定义的变量若需要出现在线程内则该线程会默认的将该变量认为是final修饰的此时若该变量是基本数据类型则不能重新赋值若是引用变量则指向不能改变但是内容可以改变
int a10;
int[] arr {0};
Thread x1 new Thread(){a100; //错误Overridepublic void run(){arr[0] 100; //不报错因为指向没有变}
};
在有多个线程时main线程会最先执行然后是剩下的线程平等的竞争CPU每个线程之间都是互不等待的例如 - 在上述代码中arr[0]大概率是0因为main先执行当x1与x2进入就绪态时分配给main的时间片可能还未用完便会直接执行输出但这是大概率也有可能在main线程未执行到输出时时间片用完此时arr[0]就会改变 - 若此时我们加上join就会取消掉互不等待
此时x1执行完之后x2才会执行最后是输出注意x1.join()执行只是让其之后的等待但x2是在x1.join()之前进入的就绪态所以此时并不会让x2线程中的内容停止执行这时候就是竞争CPU了
- 从严格的物理上讲同一时刻只能有一个线程对变量进行操作但是当我们有了告诉缓存后只有在第一次对其执行的时候需要占用总线剩下的只需要在缓存中操作即可大大加快了速度与并发效率但是特也产生了并发问题 - 比如上述的两个线程对arr[0]进行1操作可能会有多种情况但是最后arr[0]的结果只能是小于等于20000的最小的结果是1 - 那么如何解决并发问题呢 - 锁机制 - synchronized 重量级重入锁 - 当synchronized锁静态方法时锁的是该方法如果别人想要调用就要先加锁且每次调用都要加锁想调用就加锁
上下文切换
**多线程一定比单线程快吗**
- 不一定因为有上下文切换 - 在产生CPU浪费的情况下多线程合适无浪费的情况下单线程合适 - 在执行的操作次数越多多线程就越快次数越少单线程相比更快如下图 原因因为线程有创建和上下文切换的开销
当执行的操作次数很少时CPU的使用率与多线程时相差不多但是多线程会有一个创建和上下文切换的开销所以总的时间就会变长当执行操作次数很多时单线程就会因为IO的时间而导致CPU在这期间会“发呆”没有操作来使用CPU导致CPU的使用率大大降低而多线程在出现IO时并不会等待IO的结束而是会直接执行其他操作只要该操作的CPU使用时间完成就直接让下一个操作来占用CPU此时CPU就会不间断的工作起来不再休息
- 线程性能测量工具 - 使用Lmbench3来测量上下文切换的时长 - 使用vmstat可以测量上下文切换的次数 - 如何减少上下文切换的次数 - 无锁并发编程多线程竞争锁时会引起上下文切换所以多线程处理数据时可以用一 些办法来避免使用锁如将数据的ID按照Hash算法取模分段不同的线程处理不同段的数据 - CAS算法Java的Atomic包使用CAS算法来更新数据而不需要加锁 - 使用最少线程数避免创建不必要的线程。比如任务很少但是创建的线程很多 - 协程 - 减少上下文切换的实战 - 通过减少线上大量WAITING的线程来减少上下文切换次数 - 第一步用jstack命令dump线程信息jsatck指令 - 第二步统计所有线程分别处于什么状态grep指令 - 第三步打开dump文件查看处于WAITINGonobjectmonitor的线程在做什么 - 第四步减少JBOSS的工作线程数找到JBOSS的线程池配置信息将maxThreads降到 100 - 第五步重启JBOSS再dump线程信息然后统计WAITINGonobjectmonitor的线程WAITING的线程少了系统上下文切换的次数就会少因为每一次从 WAITTING到RUNNABLE都会进行一次上下文的切换