java多线程基础
2015-11-02 13:29
232 查看
多线程实现
实现多线程,有两种手段,一种是继续Thread类,另外一种是实现Runable接口。class 类名 extends Thread{ 方法1; … @override public void run(){ // other code… } 属性1; … } class 类名 implements Runnable{ 方法1; … @override public void run(){ // other code… } 属性1; … }
实现Runnable接口比继承Thread类所具有的优势:
1):适合多个相同的程序代码的线程去处理同一个资源
2):可以避免java中的单继承的限制
3):增加程序的健壮性,代码可以被多个线程共享,代码和数据独立。
线程的状态
新建状态(New):当线程对象创建后,即进入了新建状态。仅仅由java虚拟机分配内存,并初始化。如:Thread t = new MyThread();
就绪状态(Runnable):当调用线程对象的start()方法,线程即进入就绪状态。java虚拟机创建方法调用栈和程序计数器,此线程做好准备等待CPU调度执行。
运行状态(Running):当CPU开始调度处于就绪状态的线程时,执行run()方法进入到运行状态。
阻塞状态(Blocked):处于运行状态中的线程由于某种原因,暂时放弃对CPU的使用权,停止执行,此时进入阻塞状态,直到其进入到就绪状态,才会再次被CPU调用以进入到运行状态。
死亡状态(Dead):线程run()方法执行完了或者因异常退出了run()方法,该线程结束生命周期。当主线程结束时,其他线程不受任何影响。
根据阻塞产生的原因不同,阻塞状态又可以分为三种:
等待阻塞 – 运行状态中的线程执行wait()方法,使本线程进入到等待阻塞状态,JVM会把该线程放入等待池中;
同步阻塞 – 线程在获取synchronized同步锁失败(因为锁被其它线程所占用),它会进入同步阻塞状态;
其他阻塞 – 通过调用线程的sleep()或join()或发出了I/O请求时,线程会进入到阻塞状态。当sleep()状态超时、join()等待线程终止或者超时、或者I/O处理完毕时,线程重新转入就绪状态。
yield()
: 正在执行的线程暂停,让出cpu资源给其他的线程,直接进入就绪状态。
sleep()
:当前线程睡眠后会进入阻塞状态,睡眠结束转入就绪状态 。
join():把指定的线程加入到当前线程,可以将两个交替执行的线程合并为顺序执行的线程。非静态
setPriority():设置优先级,优先级高的线程获取CPU资源的概率较大,java提供了10个优先级别,0~10。
Thread类提供的三个优先级静态常量:
MAX_PRIORITY =10
MIN_PRIORITY =1
NORM_PRIORITY =5
在默认情况下,main线程具有普通优先级
setDaemon():用户可以用Thread的setDaemon(true)方法设置当前线程为守护线程。
Java中有两类线程:User Thread(用户线程)、Daemon Thread(守护线程) 。用户线程即运行在前台的线程,而守护线程是运行在后台的线程。守护线程作用是为其他前台线程的运行提供便利服务,而且仅在普通、非守护线程仍然运行时才需要,比如垃圾回收线程就是一个守护线程。当VM检测仅剩一个守护线程,而用户线程都已经退出运行时,VM就会退出,因为没有如果没有了被守护这,也就没有继续运行程序的必要了。如果有非守护线程仍然存活,VM就不会退出。守护线程的特征:如果所有前台线程都死亡,后台线程会自动死亡。
守护线程并非只有虚拟机内部提供,用户在编写程序时也可以自己设置守护线程。用户可以用Thread的setDaemon(true)方法设置当前线程为守护线程。 虽然守护线程可能非常有用,但必须小心确保其他所有非守护线程消亡时,不会由于它的终止而产生任何危害。因为你不可能知道在所有的用户线程退出运行前,守护线程是否已经完成了预期的服务任务。一旦所有的用户线程退出了,虚拟机也就退出运行了。因此,不要在守护线程中执行业务逻辑操作(比如对数据的读写等)。
wait与sleep区别:
sleep静态方法,wait非静态 。
sleep方法没有释放锁,而wait方法释放了锁,使得其他线程可以使用同步控制块或者方法。
wait,notify和notifyAll只能在同步控制方法或者同步控制块里面使用,而sleep可以在任何地方使用
sleep必须捕获异常,而wait,notify和notifyAll不需要捕获异常
线程同步
1.同步代码块: synchronized (obj) { //... } 2.同步方法: public synchronized void method(){ // .... } 3.同步锁: class C { //锁对象 private final ReentrantLock lock = newReentrantLock(); ...... //保证线程安全方法 public void method() { //上锁 lock.lock(); try { //保证线程安全操作代码 } catch() { } finally { lock.unlock();//释放锁 } } }
三种方法都是执行 “加锁->访问->释放锁”操作,但是同步代码块和同步方法使用隐式的同步监视器,LOCK则是显示调用方法。
线程池
并发的线程数量很多,频繁创建和销毁线程就会消耗资源、降低系统的效率。Java核心线程池ThreadPoolExecutor类:
public ThreadPoolExecutor( int corePoolSize, //核心池大小 int maximumPoolSize, //线程池最大线程数 long keepAliveTime, //表示线程没有任务执行时最多保持多久时间会终止 TimeUnitunit, //参数keepAliveTime的时间单位 BlockingQueue<Runnable>workQueue, //阻塞队列 ThreadFactorythreadFactory, //线程工厂,主要用来创建线程 RejectedExecutionHandlerhandler);//表示当拒绝处理任务时的策略
1.默认情况下,在创建了线程池后,线程池中的线程数为0,当有任务来之后,就会创建一个线程去执行任务,当线程池中的线程数目达到corePoolSize后,就会把到达的任务放到缓存队列当中;
2.任务缓存队列已满,会尝试创建新的线程去执行任务,当线程池中的线程数目达maximumPoolSize,则会采取任务拒绝策略进行处理;
3.如果线程池中的线程数量大于 corePoolSize时,如果某线程空闲时间超过keepAliveTime,线程将被终止。
但是如果调用了allowCoreThreadTimeOut(boolean)方法,在线程池中的线程数不大于corePoolSize时,keepAliveTime参数也会起作用,直到线程池中的线程数为0;
参数:
缓存队列workQueue的类型为BlockingQueue<Runnable>,通常可以取下面三种类型:
ArrayBlockingQueue:基于数组的先进先出队列,此队列创建时必须指定大小;
LinkedBlockingQueue:基于链表的先进先出队列,如果创建时没有指定此队列大小,则默认为Integer.MAX_VALUE;
synchronousQueue:这个队列比较特殊,它不会保存提交的任务,而是将直接新建一个线程来执行新来的任务。
当线程池的任务缓存队列已满并且线程池中的线程数目达到maximumPoolSize,如果还有任务到来就会采取任务拒绝策略,通常有以下四种策略:
ThreadPoolExecutor.AbortPolicy:丢弃任务并抛出RejectedExecutionException异常。
ThreadPoolExecutor.DiscardPolicy:也是丢弃任务,但是不抛出异常。
ThreadPoolExecutor.DiscardOldestPolicy:丢弃队列最前面的任务,然后重新尝试执行任务(重复此过程)
ThreadPoolExecutor.CallerRunsPolicy:由调用线程处理该任务
线程池初始化:
prestartCoreThread():初始化一个核心线程;
prestartAllCoreThreads():初始化所有核心线程
线程池关闭:
ThreadPoolExecutor提供了两个方法,用于线程池的关闭,分别是shutdown()和shutdownNow(),其中:
shutdown():不会立即终止线程池,而是要等所有任务缓存队列中的任务都执行完后才终止,但再也不会接受新的任务
shutdownNow():立即终止线程池,并尝试打断正在执行的任务,并且清空任务缓存队列,返回尚未执行的任务
相关文章推荐
- ubuntu 14 java web服务器搭建
- MyEclipse2014的安装与破解
- java 线程池的原理分析
- java中static和final的使用
- Java_api手册
- Java下的Cookie和Session
- java作业5
- java中单引号与双引号的区别?hashcode()和equals()
- Java计算周长面积,入门
- java希尔排序
- Java中List实现之ArrayList
- Eclipse/MyEclipse常用快捷键
- spring 注解用法搜集
- java 接口类与抽象类
- struct2源码解读(1)之struts2启动
- Eclipse Project仅物理删除没有逻辑删除,导致不能重新导入
- java实现将整数转化为中文大写金额
- 搭建spring mvc + maven + hibernate
- (转)FileUtil.java 工具类
- 项目问题总结3:MyEclipse导入项目报错-"The import javax.servlet cannot be resolved"