线程与线程池
线程是什么?
- 线程是运行在进程中的一个独立实体,是CPU调度和分派的基本单位。
- 线程基本不拥有系统资源,可以与同属一个进程的其它线程共享进程所用多的全部资源
多线程是什么?
- 一个进程中多个线程的情况,我们叫做多线程。
- 多个线程会共享进程所拥有的全部资源。
减少创建线程的开销,有哪些开销?
- 关于时间,创建线程使用是直接向系统申请资源的,对操作系统来说,创建一个线程的代价是十分昂贵的, 需要给它分配内存、列入调度,同时在线程切换的时候还要执行内存换页,CPU 的缓存被 清空,切换回来的时候还要重新从内存中读取信息,破坏了数据的局部性。
- 关于资源,Java线程的线程栈所占用的内存是在Java堆外的,所以是不受java程序控制的,只受系统资源限制,默认一个线程的线程栈大小是1M(当让这个可以通过设置-Xss属性设置,但是要注意栈溢出问题),但是,如果每个用户请求都新建线程的话,1024个用户光线程就占用了1个G的内存,如果系统比较大的话,一下子系统资源就不够用了,最后程序就崩溃了。
多线程的作用
- 通过多个线程并发执行,从而提高任务处理的速度。
创建几种方式
- 继承Thread类,并复写run方法,创建该类对象,调用start方法开启线程。
- 实现Runnable接口,复写run方法,创建Thread类对象,将Runnable子类对象传递给Thread类对象。调用start方法开启线程。
- 通过Callable和Future创建线程(略)
代码学习
public static void main(String[] args) throws ExecutionException {
//Callable的返回值就要使用Future对象,Callable负责计算结果,Future负责拿到结果
//1、实现Callable接口
Callable<Integer> callable = new Callable<Integer>() {
public Integer call() throws Exception {
int i=999;
//do something
// eg request http server and process
return i;
}
};
//2、使用FutureTask启动线程
FutureTask<Integer> future = new FutureTask<Integer>(callable);
new Thread(future).start();
//3、获取线程的结果
try {
Thread.sleep(5000);// 可能做一些事情
System.out.println(future.get());
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
}
}
线程池 Executors类
- 创建固定数目线程的线程池
- 创建一个可缓存的线程池
- 定时及周期性的执行任务的线程池
-
- scheduleAtFixedRate 这个方法是不管你有没有执行完,反正我每隔几秒来执行一次,以相同的频率来执行
-
- scheduleWithFixedDelay 这个是等你方法执行完后,我再隔几秒来执行,也就是相对延迟后,以固定的频率去执行
代码学习
public static void testFixedThreadPool() {
//创建固定的线程池,使用3个线程来并发执行提交的任务。底层是个无界队列
ExecutorService executorService = Executors.newFixedThreadPool(6);
executorService.execute(new MyThread());
executorService.execute(new MyRunnable());
executorService.execute(new MyRunnable());
executorService.execute(new MyRunnable());
executorService.execute(new MyThread());
executorService.execute(new MyThread());
}
public static void testSingleThreadPool() {
//创建单线程,在任务执行时,会依次执行任务。底层是个无界队列。
ExecutorService executorService = Executors.newSingleThreadExecutor();
executorService.execute(new MyThread());
executorService.execute(new MyRunnable());
executorService.execute(new MyRunnable());
executorService.execute(new MyRunnable());
executorService.execute(new MyThread());
}
public static void testCacheThreadPool() {
//创建非固定数量,可缓存的线程池。当提交的任务数量起起伏伏时,会自动创建或者减少执行线程的数量。
//当然,重用线程是线程池的基本特征。
ExecutorService executorService = Executors.newCachedThreadPool();
executorService.execute(new MyThread());
executorService.execute(new MyRunnable());
executorService.execute(new MyRunnable());
executorService.execute(new MyRunnable());
executorService.execute(new MyThread());
}
public static void testScheduledThreadPool(){
//创建一个定时执行线程池
ScheduledExecutorService executorService = Executors.newScheduledThreadPool(30);
//1、配置任务的执行周期
//scheduleAtFixedRate 固定周期执行完毕
executorService.scheduleAtFixedRate(new MyRunnable(),0,1000,TimeUnit.MILLISECONDS);
//scheduleWithFixedDelay 上一次执行完毕之后下一次开始执行
executorService.scheduleWithFixedDelay(new MyRunnable(),0,1000,TimeUnit.MILLISECONDS);
}
public static void testSingleCacheThreadPool(){
//创建一个单个线程执行的定时器
ScheduledExecutorService executorService = Executors.newSingleThreadScheduledExecutor();
//scheduleAtFixedRate 固定周期执行完毕
executorService.scheduleAtFixedRate(new MyRunnable(),0,1000,TimeUnit.MILLISECONDS);
//scheduleWithFixedDelay 上一次执行完毕之后下一次开始执行
executorService.scheduleWithFixedDelay(new MyRunnable(),0,1000,TimeUnit.MILLISECONDS);
}
public static void testMyThreadPool(){
//自定义连接池稍微麻烦些,不过通过创建的ThreadPoolExecutor线程池对象,可以获取到当前线程池的尺寸、正在执行任务的线程数、工作队列等等。
ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(10,100,10,TimeUnit.SECONDS,new ArrayBlockingQueue<Runnable>(100));
threadPoolExecutor.execute(new MyThread());
threadPoolExecutor.execute(new MyRunnable());
threadPoolExecutor.execute(new MyRunnable());
}