1.什么是线程
线程就是进程中运行的多个子任务,是操作系统调用的最小单元
2.线程的状态
1.New:
新建状态,new
出来,还没有调用start
2.Runnable:
可运行状态,调用start
进入可运行状态,可能运行也可能没有运行,取决于操作系统的调度
3.Blocked:
阻塞状态,被锁阻塞,暂时不活动,阻塞状态是线程阻塞在进入
4.synchronized:
关键字修饰的方法或代码块(获取锁)时的状态。
5.Waiting:
等待状态,不活动,不运行任何代码,等待线程调度器调度,wait
、sleep
用来暂停当前线程的执行,以毫秒为单位,任何其它线程都可以中断当前线程的睡眠,这种情况下将抛出InterruptedException
异常
6.Timed Waiting:
超时等待,在指定时间自行返回
7.Terminated:
终止状态,包括正常终止和异常终止
3.线程的创建
线程创建的常用方法
- 1.继承Thread重写run方法
- 2.实现Runnable重写run方法
- 3.实现Callable重写call方法
4.同步方法和同步代码块
为何要使用同步?java
允许多线程并发控制,当多个线程同时操作一个可共享的资源变量时(如数据的增删改查), 将会导致数据不准确,相互之间产生冲突,因此加入同步锁以避免在该线程没有完成操作之前,被其他线程的调用,从而保证了该变量的唯一性和准确性。
- 1.同步方法
即有synchronized
关键字修饰的方法, 由于java
的每个对象都有一个内置锁,当用此关键字修饰方法时,内置锁会保护整个方法。在调用该方法前,需要获得内置锁,否则就处于阻塞状态。
代码如:
public synchronized void save(){
}
-
2.使用特殊域变量(volatile)实现线程同步
a.volatile关键字为域变量的访问提供了一种免锁机制,
b.使用volatile修饰域相当于告诉虚拟机该域可能会被其他线程更新,
c.因此每次使用该域就要重新计算,而不是使用寄存器中的值
d.volatile不会提供任何原子操作,它也不能用来修饰final类型的变量
例如:
在上面的例子当中,只需在account前面加上volatile修饰,即可实现线程同步。
//只给出要修改的代码,其余代码与上同
class Bank {
//需要同步的变量加上volatile
private volatile int account = 100;
public int getAccount() {
return account;
}
//这里不再需要synchronized
public void save(int money) {
account += money;
}
}
5.线程池ThreadPoolExecutor
线程池的工作原理:线程池可以减少创建和销毁线程的次数,从而减少系统资源的消耗,当一个任务提交到线程池时
- a. 首先判断核心线程池中的线程是否已经满了,如果没满,则创建一个核心线程执行任务,否则进入下一步
- b. 判断工作队列是否已满,没有满则加入工作队列,否则执行下一步
- c. 判断线程数是否达到了最大值,如果不是,则创建非核心线程执行任务,否则执行饱和策略,默认抛出异常