进程:是一个运行中的程序,当CPU赋予程序生命时,就是进程。是操作系统的一个任务
线程:是进程中的一个任务,是一个顺序执行流。有自己独立的堆栈,与其他线程共享进程的地址空间
多进程:相比较于古老的操作系统,现在的操作系统都是多进程的,可以同时运行多个程序
多线程:一个进程中的多个任务,可以同时进行多个顺序执行流。提高CPU的资源利用率,可以共享同一个资源(静态资源,同一个对象实例)
并发原理:
CPU在一个时间片段里只能做一件事。微观上,CPU是将时间分成很多个小的时间片段,尽可能地将时间片段平均分给多个线程。针对于某一线程来说,是走走停停断断续续的。
在宏观上,人类感觉不出,看似这些线程是同时进行的。
线程的三种创建方式:
(1)继承Thread类,重写run方法,调用start方法启动线程,进入就绪状态
(2)实现Runnable接口,重写接口里的run方法,传给Thread对象,调用start方法
(3)创建Callable子类对象,重写call方法,传给FutureTask对象,将FutureTask对象传给Thread对象,调用start方法
线程的状态:
(1)新建状态:线程的创建,任务的确定
(2)就绪状态:调用start方法,进入就绪状态,等待CPU分配时间片段
(3)运行状态:当CPU将时间片段给了线程对象后,线程开始执行任务
(4)阻塞状态:正在运行的线程,由于某种原因,放弃了CPU的使用权,即该线程放弃时间片段,进入阻塞状态
等待阻塞:运行中的线程调用wait方法,jvm将此线程放入等待池中
同步阻塞:运行中的线程想要获取同步的锁对象时,如果锁对象被其他线程占用,则jvm将此线程放入锁池中
其他阻塞:当线程中执行到阻塞方法或者是Thread.sleep()或者是其他线程的join时,此线程放弃时间片段,进入阻塞状态
(5)死亡状态:当线程执行完任务后,或者由于异常造成的run方法停止,就是死亡状态。
常用构造器:
Thread(Runnable r)
创建一个指定任务的线程对象
Thread(Runnable r,String name)
创建一个指定任务并且指定名称的线程对象
Thread(String name)
创建一个指定名称的线程对象
常用方法:
String getName()
获取线程名称
long getId()
获取线程ID
int getPriority()
获取当前线程的优先级
boolean isAlive()
查看线程状态
boolean isDaemon()
查看线程是否为守护线程(后台线程)
State getState()
查看线程状态
boolean isInterrupted()
查看线程是否被打断
void setPriority(int priority)
设置优先级
void setDaemon(boolean flag)
设置为true时是守护线程
static sleep(long time)
使当前线程放弃时间片段进入阻塞状态,time毫秒后会进入就绪状态,如果期间被打断会出现检查性异常InterruptException
void interrupted()
打断当前阻塞状态的线程对象
void join()
将当前线程A加入到线程B中,线程B进入阻塞状态,直到线程A任务结束,线程B进入就绪状态
static void yield()
线程对象让步的功能,让出时间片段,此线程进入就绪状态
线程优先级(线程调度):
多线程时,先执行的线程是由CPU的线程调度决定的。可以通过线程的优先级尽可能的让线程调度调控线程所需要的时间片段
1-10, 10为最高级别,1为最低级别,5为默认级别
Thread.MIN_PRIORITY---最小优先级
Thread.MAX_PRIORITY---最高优先级
Thread.NORM_PRIORITY--默认优先级
线程分两类:
一类是普通线程(前台线程),一类是守护线程(后台线程)。当多线程程序只剩下守护线程后,所有线程都结束。
同步锁:
当多个线程操作临界资源时,可能会出现线程安全隐患问题。如果要解决这样的问题,需要使用同步操作。线程在内部提供了一个内置的锁机制保证原子性,用于线程进行同步操作。
临界资源可能是:
(1)某一个静态变量
(2)某一个实例变量
异步操作:多线程的并发操作
同步操作:一个线程执行完,另一个线程再执行
锁:
(1)锁是一个对象,
(2)如果想进行同步操作,多个线程操作的必须是同一个锁
synchronized(锁对象的引用){需要同步的代码块}锁机制:
当一个线程进入同步的代码块后,会获得锁对象的使用权。其他线程如果执行到此处,会发现锁对象被占用,只能处于等待状态(锁池)
当线程执行完同步的代码块后,或者出现异常,都会自动释放锁。
合适的锁对象:
必须是一个引用类型,必须使多个线程都可以使用这个锁对象,因此this对象比较适合
同步代码块的范围:
(1)可以是方法内的一部分代码,可以是全部代码(相当于给方法上了锁)
(2)成员方法上添加修饰词synchronized,锁对象为this
如果一个类的所有成员方法都使用了同步关键字,当某一个线程操作了其中一个方法,另外的线程即时操作的不是这个方法,也会进入锁池
(3)静态方法上添加修饰词synchronized,锁对象为类对象
调用方法:类名.class,每一种类都有一个唯一的类对象
wait()/notify()/notifyAll()
是Object类型提供的,用来调控线程的状态的。使用位置必须是同步块中,否则会出现异常
wait()
当前获取锁对象的线程准备释放锁,给其他线程获取锁的机会
wait(long time)
当前获取锁对象的线程如果没有被通知,在延迟time毫秒后,释放锁对象
wait(long time,int naons)
比上一个方法延迟时间更加精确
notify()/notifyAll()
当前获取锁对象的线程准备释放锁,使用此方法通知处于使用wait方法等待的线程准备竞争锁对象
notify()
随机通知等待线程中的一个
notifyAll()
通知所有等待的线准备程竞争锁对象
线程池:
(1)如果每个任务都需要创建线程对象,内存开销大
(2)方便管理线程对象
原理:
一些线程的集合,线程的状态不是死亡状态,当线程池接收到外面的任务,线程池的管理器会查看是否有空闲线程,如果有就会将任务分配给它,如果没有,任务处于等待队列中
类型:ExecutorService
另一个类Executors里提供了多个静态方法来获取线程池里的对象
方法1:
static ExecutorService newSingleThreadExecutor
获取单个线程的线程池对象,内部维护了一个无界队列,用于存储任务
方法2:
static ExecutorService newFixedThreadPool(int nThreads)
创建一个固定数量线程的线程池,内部维护了一个无界队列,用于存储任务
方法3:
static ExecutorService newCachedThreadPool()
创建一个可以根据需求来创建新线程的线程池对象,如果有可重用的,会优先使用
方法4:
static ScheduledExecutorService newScheduledThreadPool(int corePoolSize)
创建一个线程池,可以进行设置延迟或定时来执行任务