1.java多线程技能
1.1.进程和多线程的概念及线程的优势
进程:进程是操做系统的基础,是一次程序的执行,是一个程序及数据在处理机上顺序执行时所发生的活动。是程序在一个数据集合上运行的过程,他是系统进行资源分配和调度的一个独立单位。
线程:进程中独立运行的子任务。
多线程优势:最大限度的利用CPU的空闲时间来处理其余子任务。
1.2. 使用多线程
直接使用java main方法运行程序,也运行了一个线程。一个进程至少有一个线程在运行。
实现多线程的方式主要有两种: 继承Thread类,实现Runnable接口。其实Thread 也是实现了Runnable接口,二者没有本质的区别。
直接启动run方法,没有异步效果,即便起了不少线程也会是单线程执行的模式,指向start方法才会异步执行,将线程对象交给线程规划器执行。
执行start的顺序,不表明线程启动的顺序,start方法只是通知线程调度器此线程已经准备就绪,具体顺序由jvm控制。
为了能够继承其余的类,通常采用实现Runnable接口的方式编写多线程代码。
非线程安全:多个线程对同一个对象中的同一个实例变量进行操做时,会出现值被更改,值被同步的状况,进而影响程序的指向流程
jvm中 i - - 分三步执行,取得i值,计算i-1,对i进行复制。多个线程同时访问,就会出现问题
1.3. currentThread()方法
返回代码段正在被哪一个线程调用的信息。
1.4. isAlive()方法
判断当前线程是否处于活动状态
线程处于正在运行,或者准备开始运行的阶段,就认为线程是存活测状态。
currentThread 表示当前执行的线程,this表示当前的对象
1.5.sleep()方法
在指定的毫秒数内让当前正在执行的线程 休眠。
1.6. getId()方法
取得线程的惟一标识
1.7. 中止线程
使用退出标志,使线程征程退出,run执行完以后退出
使用stop强行中止线程, 不推荐这么使用,stop,suspend及resume都是做废过时的方法
使用interrupt方法中断线程,interrupt只是给当前线程打了一个中止标志,并非真正的中止线程。
this.interrupted()测试当前线程是否已是中断状态,执行后具备将状态标志清除为false的功能。
this.isInterrupted()测试线程对象是否已是中断状态,不清除状态标志。
线程中抛出异常也会中止线程。
在sleep状态进入执行interrupt,会抛出,InterruptedException异常,反过来也是同样的
可使用interrupt和return结合来中止线程,不过建议使用抛异常的方式来实现线程的中止。异常能够上抛,使异常事件得以传播。
1.8. 暂停线程
suspend和resume方法分别是暂停和恢复线程的运行,可是极易形成,公共的同步对象独占,其余线程没法访问到这个对象,问题不少,建议不适用。
1.9 yield()方法
放弃当前的CPU资源。可是本身会进入就绪队列,因此可能放弃以后又立刻占有CPU资源
1.10. 线程的优先级
优先级越高的线程,就越容易获得CPU资源,可是具体由谁来执行仍是由线程规划器来肯定执行的线程。使用setPrisetPriority()方法设置优先级,级别为1-10
线程的优先级具备继承性,执行线程默认和启动线程具备相同的优先级
线程的优先级和代码的执行顺序无关,可是CPU尽可能将执行资源让给优先级比较高的线程。
线程优先级的特性:继承性,规则性和随机性
1.11. 守护线程
线程有两种:用户线程和守护线程
守护线程是一种特殊的线程,没有非守护线程时,守护线程会自动销毁。
垃圾回收机制就是典型的守护线程,使用setDaemon(true)就能够将线程设置为守护线程。
2. 对象及变量的并发访问
2.1. synchronized同步方法
方法内部的变量永远是安全的,由于做用域就在方法内
两个线程访问同一个对象的同步方法时,必定是线程安全的。
关键字synchronized取得的锁都是对象锁,而不是将一段代码或者方法当作锁
只有共享资源的读写访问才须要同步化,若是不是共享资源,就不须要同步
锁重入:synchronized具备锁重入的功能,当一个线程获取对象锁以后,再次请求此对象锁时是能够再次获得该对象的锁的。存在子父类继承关系时,子类彻底能够经过可重入锁调用父类的同步方法。
当一个线程执行的代码出现异常时,其所持有的锁会自动释放。
同步不具体继承性,子类方法没法继承父类的synchronized关键字
2.2. synchronized同步语句块
synchronized申明方法是有弊端的,只有当方法执行完毕以后才会释放对象锁。使用同步块的话能够这样的问题。
当两个并发线程访问同一个对象的synchronized(this) 同步代码块时,一段时间内只有一个线程被执行,另外一个线程必须等待当前线程执行完这个代码执行完之后才能执行该该代码。
当一个线程访问objec的synchronized(this)同步代码块时,其余线程对同一个Object中其余全部的同步代码块的访问都会被阻塞。
synchronized(非this对象)代码块的内容和同步方法是异步的。
synchronized关键字加到static 静态方法上时,是给Class加锁,加在非静态方法时时给对象加锁
死锁:互相等待对方释放锁
若是同时持有相同的锁,那么这些线程就是同步的,若是分别获取对象锁,这些线程就是异步的。
2.3. volatile 关键字
主要做用是使变量在多个线程中可见。强制从公共堆栈中取得变量的值,而不是从私有数据栈中取得变得值。
volatile最致命的缺点就是不支持原子性。
原子操做是不能分割的总体,没有其余线程可以中断或者检查原子操做中的变量。使用AtomicInteger实现原子性
3. 线程间的通讯。
3.1. 等待/通知 机制
经过while循环侦测某一个条件,缺点是浪费CPU资源
经过wait,notify 等待、通知机制实现线程的通讯,wait的做用是使当前执行的线程进行等待。
在调用wait以前,线程必须得到该对象的对象级别锁,即只能在同步方法或同步快中调用wait方法,在执行wait方法以后,当前线程释放锁。
notify也要在同步方法或者同步方法块中调用,在调用以前,线程也必须得到该对象的对象级别锁。
执行notify方法以后,当前线程也不会立刻释放该锁,呈wait状态的线程也不会立刻得到该对象锁,须要等到notify线程将程序执行完毕。
notify能够随机唤醒等待队列中等待同一共享资源的一个线程,并使该线程进入等待状态。notifyAll方法可使全部的正在等待队列中等待统一共享资源的的所有线程从等待状态退出。
方法wait执行完以后,锁会被自动释放,可是notify方法被执行以后,锁不会被释放,而须要等待线程被执行完。wait(long)方法会在等待必定时间后自动唤醒,固然也能够notify唤醒
生产者消费者问题建议看书。
3.2.方法join的使用
等待线程对象销毁执行。方法join具备使线程排队运行的做用,有点相似同步的效果。
join(long)设置等待的时间。join(long)内部使用wait实现,因此会释放锁,sleep(long)却不释放锁。
3.3 类ThreadLocal的使用
为每一个线程绑定本身的值。数据具备隔离性。
4. lock 的使用
ReenTrantLock类的使用,在须要同步的代码前使用lock.lock(),结束处使用lock.unlock()释放锁
关于这块,建议看书。主要讲等待/通知的另一种实现方式。
能够参考书籍和慕课网
主要讲解
schedule(TimerTask task, Date time)
schedule(TimerTask task, Date firstTime, long period)
schedule(TimerTask task, long delay)
schedule(TimerTask task, long delay, long period)
scheduleAtFixedRate(TimerTask task, long delay, long period)
6. 单例模式和多线程
主要讲解 单例模式在多线程中的安全性
7. 拾遗增补
7.1. 线程的状态
NEW 至今还没有启动的
RUNNABLE 正在java虚拟机中执行的线程
BLOCKED 受阻塞并等待某个监控器锁的线程
WAITTING 无限期的等待另外一个线程来执行某一个特定操做的线程
TIME_WAITING 等待一个线程执行取决于指定等待时间
TERMINATED 已退出的线程
7.2 线程租
能够将线程归属到某一个线程组中,线程组中能够拥有线程对象,也能够拥有线程组,组中还能够有线程。
线程组能够批量管理线程或者线程组对象,有效的对线程或线程组对象进行组织。