第4章 Java并发编程的基础
线程的优先级:
线程的优先级越高,占用CPU的能力越强;
线程中断:
调用线程对象的interrupt()函数后,线程并不会立即中断,而是将线程的中断标识设为true,只有遇到阻塞函数(sleep()、wait()、join())时,才停止阻塞,抛出异常,并将中断标识重置为false;
如何正确中断线程:
1.使用阻塞函数捕获中断,在异常处理中跳出任务,使线程结束运行;
class Runner implements Runnable{
@Override
public void run() {
while (true){
try {
Thread.sleep(2);
} catch (InterruptedException e) {
return;
}
}
}
}
2.使用isInterrupted()判断线程是否处于中断状态,若是中断状态则跳出任务,使线程结束运行;
class Runner implements Runnable{
@Override
public void run() {
while (true){
if (Thread.currentThread().isInterrupted()){
return;
}
}
}
}
3.使用中断标识;
class Runner implements Runnable{
public volatile boolean on = true;
@Override
public void run() {
while (true){
if (on == false){
return;
}
}
}
}
线程获取锁状态变化:
线程获取锁状态变化1.运行中的线程尝试获取锁,若获取成功则继续运行,获取失败则进入同步队列;
2.notify()将等待队列的首节点加入同步队列,notifyAll()将等待队列的所有节点加入同步队列;
3.同步队列的首节点获取同步状态成功,即对应线程获取锁成功;
4.同步队列首节点的后续节点继续通过自旋来获取同步状态;
线程间通信:
多个线程相互配合完成计算任务;
通信方式:
1.使用volatile变量作为信号量;
2.使用synchronized进行锁同步;
3.使用wait()和notify()进行通信;
//线程1
synchronized(lock){
while(条件不满足 ){
lock.wait();
}
doSomething();
}
//线程2等待超时
synchronized(lock){
while(条件不满足 || remainTime > 0){
lock.wait(remain)
remainTime = futureTime - notTime;
}
}
//线程3
synchronized(lock){
改变条件;
lock.notify();
}
使用wait()和notify()时线程的状态变化
线程的状态变化
a.RUNNING状态的线程获取锁失败则进入BOLOCKED状态;
b.RUNNING状态的线程调用wait()方法后进入WAITING状态;
c.WAITING状态的线程被别的线程notify()后进入BLOCKED状态;
d.BLOCKED状态的线程获取锁成功后进入RUNNING状态;
4.使用并发计数器CountDownLatch阻塞线程;
public class CountDownLatchTest {
//计数器初始值为2
static CountDownLatch countDownLatch = new CountDownLatch(2);
public static void main(String[] args){
Thread thread1 = new Thread(new Runner(), "thread 1");
Thread thread2 = new Thread(new Runner(), "thread 2");
try {
thread1.start();
thread2.start();
//main线程阻塞,直到计数器值为0时被唤醒
countDownLatch.await();
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("main thread");
return;
}
static class Runner implements Runnable{
@Override
public void run() {
try {
Thread.sleep(2000);
System.out.println(Thread.currentThread().getName());
//计数器减一
countDownLatch.countDown();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
数据库连接池示例:
数据库连接池1.初始化一定数量的连接对象放入队列中;
2.多个线程并发的取出、归还conn对象;
3.通过加锁来解决并发问题;
线程池示例:
线程池1.多个worker线程并发从job队列中获取job;
2.job队列为空时worker线程进入waiting状态,往job队列中添加job时notify()等待的线程,取出job并执行;
3.worker线程从非空的job队列中取出job,然后执行job;
缺点:不能指定job到指定的worker线程执行;