目录
基础概念
- 进程:操作系统进行资源分配的最小单元,资源包含(CPU,内存,磁盘IO等)。比如:打开一个Office就是开启了一个进程
- 线程:CPU调度的最小单元,线程不能脱离进程存在。同一个进程中的多个线程共享进程的全部资源,每个线程仅仅只有很少部分私有资源(程序计数器,虚拟机栈,本地方法栈)。比如:打开多个word文档
- 多核心:一个芯片(CPU)上集成多个处理器核心,按照正常情况一个核心运行一个线程
- 多线程:让同一个处理器上的多个线程同步执行并共享处理器的执行资源,目前核心数:线程数 = 1:2
- 时间片轮转调度(RR算法):一种最古老、最简单、最公平且使用最广的算法,又称RR调度。每个进程被分配一个时间段,称作它的时间片,即该进程允许运行的时间
- 结论可以归结如下:时间片设得太短会导致过多的进程切换,降低了CPU效率:而设得太长又可能引起对短的交互请求的响应变差。将时间片设为100ms通常是一个比较合理的折衷。进程进行上下文切换是一个很耗时的操作
- 并发量:单位时间内处理的量,不能脱离单位时间
- 并发:指应用能够交替执行不同的任务,比如单CPU核心下执行多线程并非是同时执行多个任务,如果你开两个线程执行,就是在你几乎不可能察觉到的速度不断去切换这两个任务,已达到"同时执行效果",其实并不是的,只是计算机的速度太快,我们无法察觉到而已.
- 并行:指应用能够同时执行不同的任务,例:吃饭的时候可以边吃饭边打电话,这两件事情可以同时执行
两者区别:一个是交替执行,一个是同时执行.
Java的多线程
多线程的好处
- 充分利用CPU的资源,减少CPU的空闲时间。1.6G的一个电脑,CPU执行一个指令的时间约为0.6纳秒(1秒= 1 0 9 {10^9} 109纳秒)
- 加快响应用户的时间,一个任务分成多个线程去执行,然后合并。减少整体的执行时间
- 可以使你的代码模块化,异步化,简单化。将相同和不同的模块进行拆分,如:下订单,发邮件,发短信等
多线程程序的注意事项
- 因为多个线程共享一个进程里面的所有资源,那么就可能带来线程安全问题,多个线程同时对一个共享全局变量、静态变量进行修改时(哪怕是最简单的 count++),也会造成数据的不准确
- 为了解决线程安全问题,加入了Java的锁机制,在同一个时刻保证只有一个线程访问共享变量,这样就不会有数据不准确问题,但是同时又会带来死锁问题。不同的线程都在等待那些根本不可能被释放的锁,如:两个线程相互持有对方需要的锁,又相互等待对方释放锁。
- 线程太多了会将服务器资源耗尽形成死机当机,每个线程运行都需要系统资源,系统内存以及CPU的“过渡切换”。解决这个问题,尽量用线程池,如果数据库连接池,资源池(资源库)等
Java天生就是多线程,就比如一个简单的main函数,JVM就会开启几个线程
public class OnlyMain {
public static void main(String[] args) {
//Java 虚拟机线程系统的管理接口
ThreadMXBean threadMXBean = ManagementFactory.getThreadMXBean();
// 不需要获取同步的monitor和synchronizer信息,仅仅获取线程和线程堆栈信息
ThreadInfo[] threadInfos =
threadMXBean.dumpAllThreads(true, true);
// 遍历线程信息,仅打印线程ID和线程名称信息
for (ThreadInfo threadInfo : threadInfos) {
//1 纳秒 nanoseconds = 10的负9次方秒,计算CPU及各个硬件所运行的速度的运行单位。
System.out.println("[" + threadInfo.getThreadId() + "] " + threadInfo.getThreadName()+" times:"+threadMXBean.getThreadCpuTime(threadInfo.getThreadId()));
// StackTraceElement[] stackTrace = threadInfo.getStackTrace();
// for(StackTraceElement element : stackTrace) {
// System.out.println("class:"+element.getClassName()+"-method:"+element.getMethodName());
// }
}
}
}
运行结果:
cn.enjoyedu.ch1.base.OnlyMain
[6] Monitor Ctrl-Break times:31250000 //监控Ctrl-Break中断信号的
[5] Attach Listener times:0 //内存dump,线程dump,类信息统计,获取系统属性等
[4] Signal Dispatcher times:0 // 分发处理发送给JVM信号的线程
[3] Finalizer times:0 // 调用对象finalize方法的线程
[2] Reference Handler times:0 //清除Reference的线程
[1] main times:250000000 //main线程,用户程序入口
线程启动
- X extends Thread //继承Thread类
- X implements Runnable //实现Runnable接口
X.start() //启动线程的唯一入口 --仅仅是使线程进入准备阶段,等待CPU分配时间片后,执行
X.run() //仅仅是线程处理事件的方法,不是启动线程的方法,就相当于一个普通方法
注 意 : s t a r t ( ) 方 法 不 能 重 复 调 用 , 见 下 面 源