今天开始来学习一下有关Java多线程的知识,主要有如下知识点:android
进程与线程
线程的生命周期
中断线程
线程池
什么是进程?
进程就是在运行过程当中的程序,就好像手机运行中的微信,QQ,这些就叫作进程。缓存
什么是线程?
线程就是进程的执行单元,就好像一个音乐软件能够听音乐,下载音乐,这些任务都是由线程来完成的。微信
进程与线程的关系
一个进程能够拥有多个线程,一个线程必需要有一个父进程。
线程之间共享父进程的共享资源,相互之间协同完成进程所要完成的任务。
一个线程能够建立和撤销另外一个线程,同一个进程的多个线程之间能够并发执行。多线程
新建(New)
当线程实例被new出来以后,调用start()方法以前,线程处于新建状态。并发
可运行(Runnable)
当线程实例调用start()方法以后,线程调度器分配处理器资源以前,线程处于可运行状态
或者线程调度器分配处理器资源给线程以后,线程处于运行中状态,这两种状况都属于可运行状态。性能
等待(Waitting)
当线程处于运行状态时,线程执行了obj.wait()或Thread.join()方法、LockSupport.park()
以及Thread.sleep()时,线程处于等待状态。学习
超时等待(Timed Waitting)
当线程处于运行状态时,线程执行了obj.wait(long)、 Thread.join(long)、LockSupport.parkNanos、
LockSupport.parkUntil以及Thread.sleep(long)方法时,线程处于超时等待状态。this
阻塞(Blocked)
当线程处于运行状态时,获取锁失败,线程进入等待队列,同时状态变为阻塞。spa
终止(Terminated)
当线程执行完毕或出现异常提早结束时,线程进入终止状态线程
注意:在任何给定时刻,一个可运行的线程可能正在运行也可能没有运行(这就是为何将这个状态称为可运行而不是运行)。
interrupt
方法能够用来请求终止线程。
当对一个线程调用interrupt方法时,线程的中断状态将被置位为true。这是每个线程都具备的boolean标志。
每一个线程都应该不时地检查这个标志,已判断线程是否被中断。
public void interrupt() { if (this != Thread.currentThread()) checkAccess();//检查权限 synchronized (blockerLock) { //判断线程是否被阻塞 Interruptible b = blocker; if (b != null) { interrupt0(); b.interrupt(this);//若是是阻塞线程,则把中断状态设为false后返回 return; } } interrupt0();//不然把中断状态设为true }
若是线程被阻塞,就没法检测中断状态。
当在一个被阻塞的线程(调用sleep或wait)上调用interrupt方法时,阻塞调用将会被Interrupt Exception异常中断。
若是阻塞线程调用了interrupt()方法,那么会抛出异常,设置标志位为false,同时该线程会退出阻塞的。(利用这个特性能够打破死锁)
interrupted
方法是一个静态方法,它检测当前的线程是否被中断。调用interrupted方法会清除该线程的中断状态。isInterrupted
方法是一个实例方法,可用来检测是否有线程被中断。调用这个方法不会改变中断状态。当须要执行的任务增多时,单个线程是知足不了需求的,此时就须要建立多个线程来完成须要。
多线程的最大好处就在于提升CPU的利用率和提升执行效率,同时也存在着一些弊端:频繁的建立和销毁线程会产生不少的性能开销。
为了解决这个问题,线程池孕育而生。
在Java中,线程池的代码起源之Executor(翻译过来就是执行者)注意:这是一个接口。
Executor有一个ExecutorService子接口
。实际上,通常说线程池接口,基本上说的是这个ExecutorService。
ExecutorService接口的默认实现类为ThreadPoolExecutor
(翻译过来就是线程池执行者)。
翻译过来就是线程池执行器,它是线程池的真正实现,构造方法提供了一些参数来配置线程池。
public ThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue<Runnable> workQueue, ThreadFactory threadFactory)
corePoolSize
:线程池中核心的线程数。
核心线程默认状况下会一直存活在线程池中,即便这个核心线程啥也不干(闲置状态)。
若是指定ThreadPoolExecutor的allowCoreThreadTimeOut这个属性为true,那么核心线程若是不干活(闲置状态)的话,超过必定时间( keepAliveTime),就会被销毁掉。
maximumPollize
:线程池所能容纳的最大线程数。超过限制,新线程会被阻塞。
keepAliveTime
:一个非核心线程,若是不干活(闲置状态)的时长,超过这个参数所设定的时长,就会被销毁掉。可是,若是设置了allowCoreThreadTimeOut = true,则会做用于核心线程。
unit
:超时等待时间单位。
workQueue
:线程池中的任务队列。每次执行execute()会把runnable对象存储在这个队列中。若是队列满了,则新建非核心线程执行任务。
threadFactory
:线程工厂,为线程池提供建立新线程的功能。
ThreadPoolExecutor poolExecutor; //初始化一个线程池 poolExecutor = new ThreadPoolExecutor(corePoolSize: 3, maximumPoolSize: 5, keepAliveTime: 30, TimeUnit.SECONDS, new ArrayBlockingQueue<Runnable>( capacity: 2)); //向线程池中添加任务 poolExecutor.execute(new Runnable() { public void run() { });
首先咱们初始化一个线程池后,便可调用execute
这个方法,里面传入Runnable便可向线程池添加任务。
问题又来了,既然线程池新添加了任务,那么线程池是如何处理这些批量任务?
Executors提供了建立经常使用线程池的静态方法,接下也会大概讲解一下经常使用的四种线程池:
FixedThreadPool
建立一个定长线程池,可控制线程最大并发数,超出的线程会在队列中等待。
public static ExecutorService newFixedThreadPool(int nThreads){ return new ThreadPoolExecutor(nThreads, nThreads keepAliveTime: OL, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<Runnable>()); }
特色:
CachedThreadPool
建立一个可缓存线程池,若是线程池长度超过处理须要,可灵活回收空闲线程,若无可回收,则新建线程。
public static ExecutorService newCachedThreadPool() { return new ThneadPoolExecutor(corePoolSize: 0, maximumPoolSize: Integer.MAX VALUE, keepAliveTime: 60L, TimeUnit. SECONDS, new SynchronousQueue<Runnable>(); }
特色:
ScheduledThreadPool
建立一个定长任务线程池,支持定时及周期性任务执行。
public static ScheduledExecutorService newScheduledThreadPool(int corePoolSize) { return new ScheduledThreadPoolExecutor(corePoolSize); }
特色:
SingleThreadExecutor
建立一个单线程的线程池,它只会用惟一的工做线程来执行任务,保证全部任务按照指定顺序(FIFO, LIFO, 优先级)执行。
public static ExecutorService newSingleThreadExecutor() { return new FinalizableDelegatedExecutorService(new ThreadPoolExecutor(1, 1, keepAliveTime: 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<Runnable>())); }
特色:
有关多线程暂且说到这里,先对多线程有个初步的认识,后面会深刻研究多线程。
参考:Java线程池