首先我们要知道一个事情:
什么是线程,什么是进程?
线程是程序中一个单一的顺序控制流程。进程内一个相对独立的、可调度的执行单元,是系统独立调度和分派CPU的基本单位指运行中的程序的调度单位。在单个程序中同时运行多个线程完成不同的工作,称为多线程。
进程是正在运行的程序的实例,或者:进程是一个具有一定独立功能的程序关于某个数据集合的一次运行活动。
Java 线程的周期(五个状态):
- New 新建一个线程(创建一个线程,但是没有任何可运行的实体)
- Runnable 线程就绪(将程序变量实体放在线程中)
- Running 运行(运行放入的程序)
- Blocked 阻塞(程序暂停,等待自动唤醒或者被动唤醒)
- Dead 结束(程序运行结束或者异常而退出)
Java线程的实现(三种方式)
- 继承Thread类
class MyFirsetThread extends Thread{
private int i = 0;
@Overrider
public void run(){
for(i=0;i<=100;i++){
System.out.print(Thread.currentThread().getName() + i);
}
}
}
- 重写run方法
class MyFirstThread implements Runnable{
private int i = 0;
public void run(){
for(i=0;i<=100;i++){
Sysout.out.print(Thread.currentThread().getName()+i);
}
}
}
- 使用Callable和Future接口创建线程
Callbale: 创建Callable接口的实现类并实现clall() 方法;
使用FutureTask 类来包装callable实现类的对象,并以此FutureTask对象作为Thread对象的Target来创建线程
class MyCallable implements Callable {
private int i=0;
@Override
public Integer call() throws Exception {
int sum=0;
for(i=0;i<10;i++){
System.out.println(Thread.currentThread().getName()+" "+i);
sum++;
}
return sum;
}
}
线程的具体实现:
public
static
void
main(String[] args) {
Callable myCallabel=
new
MyCallable();
FutureTask ft=
new
FutureTask(myCallabel);
System.
out
.println(Thread.
currentThread
().getName()+" "+i);
Thread th=
new
Thread(ft);
th.start();
- int sum = ft.get(); //取得新创建的线程中的call()方法返回的 System.out.println("sum = " + sum);
- } catch (InterruptedException e) {
- } catch (ExecutionException e) {
|
Thread 和
Runnable两种实现方式
继承
Thread接口 或者实现Runnable两种方式
具体实现的时候
Thread :
Thread firstThread= new MyFirstThread();
firstThread.start();
Runnable:
Runnable second= new MyFirstRunnable();
firstT.start();
|
线程池 :
转载:Java-线程池专题
什么是线程池: java.util.concurrent.Executors提供了一个 java.util.concurrent.Executor接口的实现用于创建线程池
多线程技术主要解决处理器单元内多个线程执行的问题,它可以显著减少处理器单元的闲置时间,增加处理器单元的吞吐能力。
假设一个服务器完成一项任务所需时间为:T1 创建线程时间,T2 在线程中执行任务的时间,T3 销毁线程时间。
如果:T1 + T3 远大于 T2,则可以采用线程池,以提高服务器性能。
一个线程池包括以下四个基本组成部分:
1、线程池管理器(ThreadPool):用于创建并管理线程池,包括 创建线程池,销毁线程池,添加新任务;
2、工作线程(PoolWorker):线程池中线程,在没有任务时处于等待状态,可以循环的执行任务;
3、任务接口(Task):每个任务必须实现的接口,以供工作线程调度任务的执行,它主要规定了任务的入口,任务执行完后的收尾工作,任务的执行状态等;
4、任务队列(taskQueue):用于存放没有处理的任务。提供一种缓冲机制。
线程池技术正是关注如何缩短或调整T1,T3时间的技术,从而提高服务器程序性能的。它把T1,T3分别安排在服务器程序的启动和结束的时间段或者一些空闲的时间段,这样在服务器程序处理客户请求时,不会有T1,T3的开销了。
线程池不仅调整T1,T3产生的时间段,而且它还显著减少了创建线程的数目,看一个例子:
假设一个服务器一天要处理50000个请求,并且每个请求需要一个单独的线程完成。在线程池中,线程数一般是固定的,所以产生线程总数不会超过线程池中线程的数目,而如果服务器不利用线程池来处理这些请求则线程总数为50000。一般线程池大小是远小于50000。所以利用线程池的服务器程序不会为了创建50000而在处理请求时浪费时间,从而提高效率。
常见线程池:
- newSingleThreadExecutor
单个线程的线程池,即线程池中每次只有一个线程工作,单线程串行执行任务
- newFixedThreadExecutor(n)
固定数量的线程池,没提交一个任务就是一个线程,直到达到线程池的最大数量,然后后面进入等待队列直到前面的任务完成才继续执行
- newCacheThreadExecutor(推荐使用)
可缓存线程池,当线程池大小超过了处理任务所需的线程,那么就会回收部分空闲(一般是60秒无执行)的线程,当有任务来时,又智能的添加新线程来执行。
- newScheduleThreadExecutor
大小无限制的线程池,支持定时和周期性的执行线程
线程池的作用:
线程池作用就是限制系统中执行线程的数量。
根据系统的环境情况,可以自动或手动设置线程数量,达到运行的最佳效果;少了浪费了系统资源,多了造成系统拥挤效率不高。用线程池控制线程数量,其他线程排队等候。一个任务执行完毕,再从队列的中取最前面的任务开始执行。若队列中没有等待进程,线程池的这一资源处于等待。当一个新任务需要运行时,如果线程池中有等待的工作线程,就可以开始运行了;否则进入等待队列。
为什么要用线程池:
减少了创建和销毁线程的次数,每个工作线程都可以被重复利用,可执行多个任务。
数据库连接池:
转载:https://www.cnblogs.com/xdp-gacl/p/4002804.html
一、应用程序直接获取数据库连接的缺点
用户每次请求都需要向数据库获得链接,而数据库创建连接通常需要消耗相对较大的资源,创建时间也较长。假设网站一天10万访问量,数据库服务器就需要创建10万次连接,极大的浪费数据库的资源,并且极易造成数据库服务器内存溢出、拓机。如下图所示:
二、使用数据库连接池优化程序性能
2.1、数据库连接池的基本概念
数据库连接是一种关键的有限的昂贵的资源,这一点在多用户的网页应用程序中体现的尤为突出.对数据库连接的管理能显著影响到整个应用程序的伸缩性和健壮性,影响到程序的性能指标.数据库连接池正式针对这个问题提出来的.数据库连接池负责分配,管理和释放数据库连接,它允许应用程序重复使用一个现有的数据库连接,而不是重新建立一个。如下图所示:
数据库连接池在初始化时将创建一定数量的数据库连接放到连接池中, 这些数据库连接的数量是由最小数据库连接数来设定的.无论这些数据库连接是否被使用,连接池都将一直保证至少拥有这么多的连接数量.连接池的最大数据库连接数量限定了这个连接池能占有的最大连接数,当应用程序向连接池请求的连接数超过最大连接数量时,这些请求将被加入到等待队列中.
数据库连接池的最小连接数和最大连接数的设置要考虑到以下几个因素:
- 最小连接数:是连接池一直保持的数据库连接,所以如果应用程序对数据库连接的使用量不大,将会有大量的数据库连接资源被浪费.
- 最大连接数:是连接池能申请的最大连接数,如果数据库连接请求超过次数,后面的数据库连接请求将被加入到等待队列中,这会影响以后的数据库操作
- 如果最小连接数与最大连接数相差很大:那么最先连接请求将会获利,之后超过最小连接数量的连接请求等价于建立一个新的数据库连接.不过,这些大于最小连接数的数据库连接在使用完不会马上被释放,他将被放到连接池中等待重复使用或是空间超时后被释放.