线程是操作系统能够进行运算调度的最小单位。
是指从软件或者硬件上实现多个线程并发执行的技术。具有多线程能力的计算机因有硬件支持而能够在同一时间执行多于一个线程,进而提升整体处理性能。多线程实现的两种方式,一实现runnable接口,二继承thread类,重写run()方法。调用对象的start()的方法启动线程。实现runnable接口访问当前线程必须使用thread.currentthread()方法;继承thread类的话,使用this获取当前线程。
1.1thread类中start与run方法的区别
start方法是用来启动新创建的线程,而且start方法内部调用了run()方法,当你调用run方法的时候在会在原来中的线程调用,没有新的线程启动,不能对同一个线程对象两次调用start方法。
1、新建状态(New):新创建了一个线程对象。
2、就绪状态(Runnable):线程对象创建后,其他线程调用了该对象的start()方法。该状态的线程位于可运行线程池中,变得可运行,等待获取CPU的使用权。
3、运行状态(Running):就绪状态的线程获取了CPU,执行程序代码。
4、阻塞状态(Blocked):阻塞状态是线程因为某种原因放弃CPU使用权,暂时停止运行。直到线程进入就绪状态,才有机会转到运行状态。阻塞的情况分三种:
(一)、等待阻塞:运行的线程执行wait()方法,JVM会把该线程放入等待池中。
(二)、同步阻塞:运行的线程在获取对象的同步锁时,若该同步锁被别的线程占用,则JVM会把该线程放入锁池中。
(三)、其他阻塞:运行的线程执行sleep()或join()方法,或者发出了I/O请求时,JVM会把该线程置为阻塞状态。当sleep()状态超时、join()等待线程终止或者超时、或者I/O处理完毕时,线程重新转入就绪状态。
5、死亡状态(Dead):线程执行完了或者因异常退出了run()方法,该线程结束生命周期。
1.3sleep方法和wait方法的区别
sleep方法是静态的方法,wait方法是非静态方法。
sleep方法在时间到之后会自己醒来的,但是wait不能,必须要其他线程通过notify()方法来让他醒来。sleep方法通常用在不需要等待资源情况下的阻塞,像等待线程和数据库连接的情况一般用wait方法。
1.4同步代码块
synchronized(对象)
{
}
好处:解决线程的安全问题
弊端:都会判断同步锁,降低效率
使用前提:多个线程使用同一个锁
2.0线程池
线程池包括以下及部分
1、线程池管理器(ThreadPool):用于创建并管理线程池,包括 创建线程池,销毁线程池,添加新任务;
2、工作线程(PoolWorker):线程池中线程,在没有任务时处于等待状态,可以循环的执行任务;
3、任务接口(Task):每个任务必须实现的接口,以供工作线程调度任务的执行,它主要规定了任务的入口,任务执行完后的收尾工作,任务的执行状态等;
4、任务队列(taskQueue):用于存放没有处理的任务。提供一种缓冲机制。
2.1
corePoolSize:线程池的基本大小也就是线程池的目标大小,即在没有任务执行时线程池的大小( 线程池维护线程的最少数量)
maximunPoolSize:线程池最大大小,表示可同时活动的线程数量的上限
keepAliveTime:存活时间,如果某个线程的空闲时间超过了存活时间,那么将被标记为可回收的
timeUnit: 线程池维护线程所允许的空闲时间的单位
workQueue:线程池所使用的缓冲队列
threadFactory:线程工厂(可以自定义见博文“自定义线程工厂”)
handler:线程池对拒绝任务的处理策略(饱和策略)
2.2
线程池所需要的基本功能
创建线程池
关闭线程池
想线程池中添加任务。
1.进程:
1.进程是程序运行的执行过程,是一个动态的概念
2.进程是资源和线程的载体,持有资源和线程,资源这里指的是内存
2.线程:
1.线程是系统中最小的执行单元,线程控制着进程的执行,一个进程最少有一个线程
2.线程共享进程的资源
3.同一进程中有多个线程
3.线程的交互:
1.线程之间的相互通信称之为线程质检单额交互
2.线程交互的两种方式:----班级同学举例
1.互斥:线程之间需要抢占资源
2.同步:线程之间的合作
4.Java对线程的支持:
1.Class Thread
2.Inteface Runnable
3.以上的类和接口中都包含了一个run()方法,提供了启动线程的方法,并且他们都基于Java.lang包
5.Thread的常用方法:
1.线程的创建:
1.Thread()
2.Thread(Runnable target)
3.Thread(String name)
4.Thread(Runnable target,String name)
2.线程的方法:
1.void start():启动线程,调用该线程的run方法
2.static void sleep(long millis):让线程休眠,指定线程休眠的时间,millis单位是毫秒
3.static void sleep(long millis,int nanos):这里指定线程的休眠时间,通过第二个参数把毫秒精确到纳秒
4.void join():使当前线程等待当前线程终止,这里没有参数表示被调用的线程一定要等待当前线程终止
5.void join(long millis):指定线程等待时间,这里的单位是毫秒
6.void join(long millis,int nanos):指定线程等待时间,这里的单位通过第二个参数把毫秒又精确到纳秒
7.static void yield():使当前线程释放处理器资源
3.获取线程引用:
1.static Thread currtThread():返回当前运行线程的引用
6.Java中的进程:
1.编译进程
2.运行进程:Java虚拟机在启动的时候有一个进程Java.exe,该进程中至少有一个线程,并且这个线程存在在main方法中,称之为主线程,还有一个线程是垃圾回收机制
7.创建线程的两种方式:
1.继承Thread类,重写Thread类中的run方法
1.重写run方法的原因:Thread类用于描述线程,该类就定义了一个功能,就是存储线程要运行的代码,该存储功能就是run方法,也就是Thread类中的run方法是用来存储线程要执行的代码
2.创建对象的同时就是创建了一个线程
3.调用start方法,启用并执行线程
2.线程都有自己默认的名称-----Thread-编号,从0开始
3.实现Runnable接口:
1.实现Runnable接口
2.覆盖接口中的run方法
3.使用Thread类建立线程对象
4.将Runnable接口的子类对象作为一个实际参数传递给Thread类的构造函数,因为run方法所指的对象是Runnable接口的子类的对象,所以要让线程指定指定对象的run
方法
5.调用Thread类中的start方法开启线程,并调用Runnable接口的子类对象中的run方法
Thread和Runnable的区别:
实际开发中我们通常采用Runnable接口来实现多线程。因为实现Runnable接口比继承Thread类有如下好处:
1. 避免继承的局限,一个类可以继承多个接口,但是类只能继承一个类。
2. Runnable接口实现的线程便于资源共享。而通过Thread类实现,各自线程的资源是独立的,不方便共享。
发现Thread类也是Runnable接口的子类。
可见, 实现Runnable接口相对于继承Thread类来说,有如下显著的好处:
(1)适合多个相同程序代码的线程去处理同一资源的情况,把虚拟CPU(线程)同程序的代码,数据有效的分离,较好地体现了面向对象的设计思想。
(2)可以避免由于Java的单继承特性带来的局限。我们经常碰到这样一种情况,即当我们要将已经继承了某一个类的子类放入多线程中,由于一个类不能同时有两个父类,所以不能用继承Thread类的方式,那么,这个类就只能采用实现Runnable接口的方式了。
(3)有利于程序的健壮性,代码能够被多个线程共享,代码与数据是独立的。当多个线程的执行代码来自同一个类的实例时,即称它们共享相同的代码。多个线程操作相同的数据,与它们的代码无关。当共享访问相同的对象是,即它们共享相同的数据。当线程被构造时,需要的代码和数据通过一个对象作为构造函数实参传递进去,这个对象就是一个实现了Runnable接口的类的实例。