什么是程序,什么是进程,什么是线程,他们有什么区别?
程序是指令和数据的有序集合,其本身并没有任何运行的含义,是一个静态的概念。
进程是一个动态的过程,是一个活动的实体。简单来说,一个应用程序得到运行就可以看作是一个进程。进程可以包含多个同时运行的线程。进程也是拥有系统资源分配的最小基本单位。
线程是进程的实体,是CPU调度和分派的最小基本单位,是比线程更小的能独立运行的基本单位。一个进程至少有一个线程。那有时候简单的一个小程序并没有用到线程,线程又从何而来?这里的线程是由CPU调用资源时产生的线程,就是我们常说的主线程(姑且理解成主函数那个代码块吧!)。线程类创建线程只是给了我们一个调度资源的机会,而不是说线程必须是我们创建,只要需要CPU调度资源就需要线程的创建,我们不创建,JVM自己创建(通常情况下就是这个主线程了)。
更深刻的了解可以看这里,比喻生动形象https://www.cnblogs.com/dreamroute/p/5207813.html
什么是线程池?
顾名思义,就是事先创建若干个可执行的线程放进一个“池(容器)”里面,需要的时候就直接从池里面取出来不需要自己创建,使用完毕也不需要销毁而是放进“池”中,从而减少了创建和销毁对象所产生的开销。
为什么使用(线程)池?
在面向对象的编程中,创建和销毁对象非常耗费时间,因为创建一个对象需要获得内存资源或者其他更多的资源。在Java中更是如此,虚拟机甚至试图跟踪每个对象,以便能够在对象销毁后进行垃圾回收。所以,提高效率的一个手段就是尽可能减少对象创建和销毁的次数,这就是“池化资源”技术产生的原因。所以,将线程资源准备好放在一个池里面提高效率呀!
线程池的使用
ExecutorService:线程池接口
ExecutorService pool(池名称) = Executors.常用线程池名;
例:
ExecutorService pool = Executors.newSingleThreadExecutor();
线程池(前四种常用吧)
- newsingleThreadExecutor
单个线程的线程池,即线程池中每次只有一个线程在工作,单线程串行执行任务
public class single {
public static void main(String[] args) {
//创建池
ExecutorService pool = Executors.newSingleThreadExecutor();
for(int i = 0;i<5;i++) {
int number = i;
//一个新线程加入池
pool.execute(new Runnable() {
@Override
public void run() {
System.out.println("现在时间是:"+System.currentTimeMillis()+"第"+number+"个线程");
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
});
}
//关闭池
pool.shutdown();
}
}
看输出在设置的时间段里每次只有一个线程执行 ,按顺序执行
- newfixedThreadExecutor(n)
固定数量的线程池,每提交一个任务就是一个线程,直到达到线程池的最大数量,然后在后面等待队列前面的线程执行或者销毁
public class fixed {
public static void main(String[] args) {
//创建池,可放置4个线程
ExecutorService pool = Executors.newFixedThreadPool(4);
for(int i = 0;i<7;i++) {
int number = i;
//将线程加入池
pool.execute(new Runnable() {
@Override
public void run() {
System.out.println("现在时间是:"+System.currentTimeMillis()+"第"+number+"个线程"+Thread.currentThread().getName());
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
});
}
}
}
此时执行并不是有序的,抢资源
- newCacheThreadExecutor
一个可缓存的线程池。当线程池超过了处理任务所需要的线程数,那么就会回收部分闲置线程(一般是闲置60s)。当有任务来时而线程不够时,线程池又会创建新的线程,当线程够时就调用池中线程。适用于大量的耗时较少的线程任务。
可能导致内存溢出,一般使用newFixedThreadPool代替
public class cache {
public static void main(String[] args) {
ExecutorService pool = Executors.newCachedThreadPool();
for (int i = 0; i < 5; i++) {
int number = i;
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
pool.execute(new Runnable() {
@Override
public void run() {
System.out.println(
System.currentTimeMillis() + "第" + number + "个线程" + Thread.currentThread().getName());
}
});
}
}
}
此时一直只有一个线程执行,因为每个时间段内总有闲置的线程。
/**
* Thread.sleep写在线程里面的时候,只是让线程在运行的过程中休眠2s,并没有运行后休眠2s
* 如果Thread.sleep写在run方法里面,for循环中依旧没有闲置的线程,会创新的线程
*/
- newScheduleThreadExecutor
一个大小无限的线程池,但是核心线程数量是固定的,非核心线程无限制,并且非核心线程一旦闲置立刻回收。此线程池支持定时以及周期性执行任务的需求,即该线程池可给定延迟执行的命令或者定时执行命令。该线程池多用于执行延迟任务或者固定周期的任务。
public class schedule {
public static void main(String[] args) {
//设置池中核心线程数量2
ScheduledExecutorService pool = Executors.newScheduledThreadPool(3);
System.out.println("现在时间"+System.currentTimeMillis());
/**
* pool.schedule(callable, delay, unit)
* callable - 要执行的功能
delay - 从现在开始延迟执行的时间
unit - 延迟参数的时间单位
*/
pool.schedule(new Runnable() {
@Override
public void run() {
System.out.println("现在时间"+System.currentTimeMillis());
}
}, 4, TimeUnit.SECONDS);//设置延迟4s执行
}
}
- newSingleThreadScheduledExecutor
创建只有一条线程的线程池,他可以在指定延迟后执行线程任务
- newWorkStealingPool
会更加所需的并行层次来动态创建和关闭线程。它同样会试图减少任务队列的大小,所以比较适于高负载的环境。同样也比较适用于当执行的任务会创建更多任务,如递归任务