Java并发
一、基础概念
线程和进程的区别:
进程是指处于运行过程中的程序,并且具有一定的独立功能。进程是系统进行资源分配和调度的一个单位。当程序进入内存运行时,即为线程。
一个进程可以拥有多个线程组合,线程是组成进程的基本单位。
-
线程状态
- New(新创建)
- Runnable(可运行)
- Blocked(被阻塞)
- Waiting(等待)
- Time waiting(计时等待)
- Terminated(被终止)
下面介绍线程状态的含义:
- 新创建线程
用new创建个新线程时,他还未开始运行,表示这还处于新创建的状态。
- 可运行线程
一旦调用start方法,线程处于runnable状态。一个可运行的线程可能正在运行也可能没有运行。
- 被阻塞线程和等待线程
当线程处于被等待或者阻塞状态时,暂时不活动,他不运行任何代码,并且只会消耗最小的资源,直到线程调度器重新激活它。
- 被终止的线程
线程因为run方法执行完毕而自然死亡、因为一个未捕获的异常终止了run方法而意外死亡
线程运行状态图
-
线程属性
- 优先级
默认情况下,一个线程继承他父线程的优先级。每当线程调度器有机会选择新线程时,他首先选择具有较高优先级的线程。
//设置线程的优先级,大小一般1-10 void setPriority(int newPriority) //当前线程处于让步状态,会调度其他优先级>=当前优先级的线程 static void yield()
- 守护线程
void setDaemon(boolean isDaemon)
通过该方法转换成守护线程,守护线程必须在线程启动之前调用。用途就是为其他线程提供服务,当只有守护线程的时候JVM就直接退出了。 -
同步
- 锁
ReentrantLock:
用可重入锁保护代码块
Lock mylock = new ReentrantLock();
mylock.lock();
try{
...
}
finally{
//保证资源一定会解锁
mylock.unlock();
}
条件对象:
需要线程安全区域可能还需要一定的条件支持。若一个线程在获得锁之后,一直在等待条件满足才能完成自己的线程,而使条件发生改变的线程正在等待获得锁。那么此时就就产生死锁。
也就是两个线程互相依赖对方资源。
解决方案:
先来了解下Condition
Condition newCondition()
//返回一个与该锁相关的条件对象
//对条件对象的操作
void await()
//将该线程放到条件的等待集合中
void signalAll()
//解除该条件的等待集合中的所有线程的阻塞状态
void signal()
//从该条件的等待集合中随机选择一个线程,解除其阻塞状态
Synchronized
锁和条件:
-
锁用来保护代码片段,任何时刻只能有一个线程执行被保护的代码
-
锁可以管理视图进入被保护代码段的线程
-
锁可以拥有一个或多个相关条件对象
-
每个条件对象管理那些已经进入被保护的代码段但还不能运行的线程
//以下如果当前对象没有获得该锁,会抛出异常 void notifyAll() //解除那些在改对象上调用wait方法的线程的阻塞状态。该方法只能在同步方法或同步代码块中调用。 void notify() //与上面的不同的是,这个这能随机选择一个线程解除其阻塞状态 void wait() //让该线程进入等待状态直到他被通知 void wait(long millis) //指定等待多少毫秒
Volatile:
volatile关键字为实例域的同步访问提供了一共免锁机制。如果声明一个域为volatile,编译器和JVM就知道该域是可能被另一个线程并发更新的。对volatile域变量更新是所有线程共享的域,还可以防止指令重排。
Volatile变量不能提供原子性,在语句执行的过程中不能保证读取、写入不被中断,不能确保线程安全。
final:
除了volatile和锁之外能安全的读取一个域,final关键字修饰的域也可以。
读写锁
ReentrantReadWriteLock适合读多写少的并发
//得到一个可以被多个读操作公用的读锁,会排斥所有的写操作
Lock readLock()
//得到一个写锁,排斥所有的读、写操作
Lock writeLock()
如何使用:
//新建个读写锁对象
ReentrantReadWriteLock reentrantReadWriteLock = new ReentrantReadWriteLock();
//获取读锁
Lock readLock = reentrantReadWriteLock.readLock();
//获取写锁
Lock writeLock = reentrantReadWriteLock.writeLock();
//读操作
readLock.lock();
try{
...
}finally{
readLock.unlock();
}
//写操作
writeLock.lock();
try{
...
}finally{
writeLock.unlock();
}