CSDN话题挑战赛第2期
参赛话题:学习笔记
一、线程的概念
进程(process):操作系统上一个正在运行中的程序,进程会拥有当前程序中所有的资源数据
线程(Thread):是一个进程内部的一个执行功能单元,每个线程都有自己独立的内存空间,
一个进程内部可以有一到多个线程,进程只是拥有程序的资源,线程是负责执行具体任务的
进程内的资源是被所有线程所共享的
!
进程:公司 QQ
线程:公司内部的各个部门 多个聊天窗口和不同人聊天
二、多线程的优点
优点:
多线程并发执行,能提升系统的执行性能
1、并发(Concurrent)
操作系统会将时间片划分为很多个时间点,在每个时间点上只允许一个线程获取CPU
并进入cpu中执行他的任务,执行一段时间后,就退出cpu,下一个线程再获取cpu进入,
轮流切换来执行任务,因为时间片被切分的足够细,所以宏观上看是多个线程在同时进行的。
这种现象被称为并发,并发并不是真正意义上的同时
2,并行(parlen)
真正意义上的同时,这个过程只会出现在多核cpu上,多核cpu可以在一个时间内同时去执行多件事
缺点:
多线程在同一资源进行操作时,可能会发生线程并发问题,导致数据不安全,可以通过加锁来解决
三、线程的创建
1、继承Thread
1》创建一个类继承Thread,该类实例代表一个线程
2》重写run() 方法,在方法中写该线程主要执行的具体任务
3》创建线程实例
4》调用Start()启动线程
2、实现Runnable
1》创建一个类实现Runnable接口,该类实力代表线程要执行的任务、
2》重写run() 方法,在方法中写具体任务
3》创建任务对象
4》创建一个线程对象,将该任务对象交给线程
5》调用Start()启动线程
注意:
线程调用了start()方法之后不会立即运行,而是处于就绪状态,等待CPU为其分配时间片,
只有获得了时间片才能进入cpu中执行任务,从而调用run() 方法
四、线程池ThreadPool(创建线程的第三种方式)
1、线程池的作用
主要用于创建和管理若干个线程的一种容器,当我们需要执行任务时,可以从池中取出
线程来执行,当执行完任务后,将线程返回到池中,避免频繁的去创建和销毁线程,从而
节省空间,提升系统性能
2、自定义线程池
ThreadPoolExecutor pool=
new ThreadPoolExecutor(
核心线程数,
最大线程数,
超时(空闲,活跃)时间,
超时的时间单位,
任务队列,
线程工厂,
拒绝策略);
拒绝策略类型:
* 1》AbortPolicy:拒绝执行新的任务,并抛出异常
* 2》CallerRunsPolicy:如果线程池没有关闭,不使用线程池中的线程
* 也不会加入到任务队列,而是让当前线程直接调用run()方法来执行任务,
* 如果线程池已关闭,则直接丢弃掉该任务不执行
* 3》DiscardOldestPolicy: 如果线程池没有关闭,将任务队列中存放最久的任务
* (队首元素)移除掉,并将新的任务加入到任务队列中,如果线程池已经关闭
* 则直接丢弃掉该任务不执行
* 4》DiscardPolicy:拒绝执行任务,但是不会抛异常
3、jdk自带线程
1》单线程线程池
ExecutorService es=Executors.newSingleThreadExecutor()
只有一个核心线程,不允许创建非核心线程;
等上一个任务执行完了,才能执行下一个任务
2》固定数量线程池
ExecutorService es=Executors.newFixedThreadPool(int n);
传入的参数既是核心线程又是最大线程,
也就是不允许创建非核心线程
3》可缓存线程池
ExecutorService es=Executors.newCachedThreadPool();
没有核心线程,所有线程均为非核心线程
有多少任务就会创建多少个线程
线程最大数量为integer.max_value,
所有非核心线程空闲时间超过60S就会被回收
4》周期性线程池
ExecutorService es=Executors.newScheduledThreadPool(int n);
自己指定核心线程数
线程最大数量为integer.max_value
超时时间为0
任务队列为延迟队列
4、线程池的常用方法
1》execute(Runnable r)
将任务对象交给线程池,线程池会自动取出空闲线程来执行任务,
没有空闲线程就将任务加入到任务队列中,队列满了就触发拒绝策略
2》shutdown()
安全关闭线程池
只有等到线程池中所有线程都执行完任务后才会关闭
如果还有未执行完任务,当前方法会阻塞
3》shutdownNow();
立即关闭线程
无论线程池中是否还有未执行完的额任务,都会立即关闭线程池
会导致线程池还有未执行完的任务,返回这些未执行的线程
周期性线程中的主要方法
1》schedule(Runnable r,long delay, TimeUnit unit)
延迟指定时间后来执行这个r任务
2>scheduleAtFixedRate(Runnable command,long initialDelay,long period,TimeUnit unit);
每间隔period指定的时间后来执行一次任务
如果一个任务的执行时间超过了间隔时间,
那么在一个任务执行完成红立即执行下一个任务,
如果没有超过,那么就在指定间隔时间后执行下一个任务
3》scheduleWithFixedDelay(Runnable command,long initialDelay,long delay,TimeUnit unit);
执行周期性任务
在一个任务执行完成后,再间隔设置的时间后,
再来执行下一个任务
五、通过Callbale实现线程(线程第四种创建方法)
特点:可以得到线程的执行的任务结果
Callable使用步骤:
1》写一个实现callable接口实现类为线程所要执行的任务,
并指定泛型,泛型为任务的执行结果类型
2》创建Callable任务对象,并将该对象封装在Futuretask中
3》创建一个线程来执行Futuretask,并通过该类的get()方法来获取任务执行结果
4》也通过调用线程池的submit()方法来执行任务,
并将任务执行结果封装在Future类中
并通过Future的get()方法来获取任务的执行结果
Callable和Runnable区别
1》Callable执行任务调用Call()方法,
可以获取任务执行结果,也可以抛出异常
2》Runnable执行任务调用run()方法
不能获取任务执行结果,也不可以抛出异常