并发编程艺术
二:java 并发编程基础
程序的正确性不能依赖线程的优先级高低,因为操作环境可能会忽略线程的优先级。
start()含义:当前线程同步告知java虚拟机,只要线程规划器空闲,应立即启动调用start方法的线程。(自定义线程最好起个名字)
中断:
中断可以理解为线程的一个标示位属性,他表示一个运行中的线程是否呗其他线程进行了中断操作,
线程通过检查自身是否呗中断来进行响应,线程通过isInterrupted来进行判断是否被中断。也可以调用静态方法Thread.interrupted对当前线程的中断标示位进行复位,
虚拟机先清除中断标示,再跑出异常。
4.3 线程之间的通信
4.3.1
volatile:确保了一个变量改变会同步到主内存中去,所以其他线程看到的都是最新的。
sychronized:保证了同一时刻只能有一个线程处于同步方法或者同步块中,保证了线程对变量访问的可见性和排他性。
4.3.2 等待通知
wait()等待,notify()/notifyAll()通知。
wait/notify/notifyAll使用细节
package com.souche.sts.test;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.concurrent.TimeUnit;
/**
*
* @create: 2019-09-24 08:49
**/
public class WaitNotifyTest {
static boolean flag = true;
static Object lock = new Object();
public static void main(String[] args) throws Exception {
Thread wait = new Thread(new Wait(),"WaitIng");
wait.start();
TimeUnit.SECONDS.sleep(1);
Thread notify = new Thread(new Notify(),"notifying");
notify.start();
}
static class Wait implements Runnable {
@Override
public void run() {
synchronized (lock) {
while (flag) {
try {
System.out.println(Thread.currentThread()+"-1-"+new SimpleDateFormat("HH:mm:ss").format(new Date()));
lock.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println(Thread.currentThread()+"-2-"+new SimpleDateFormat("HH:mm:ss").format(new Date()));
}
}
}
static class Notify implements Runnable {
@Override
public void run() {
synchronized (lock) {
System.out.println(Thread.currentThread()+"-3-"+new SimpleDateFormat("HH:mm:ss").format(new Date()));
lock.notifyAll();
flag = false;
second(5);
}
synchronized (lock) {
System.out.println(Thread.currentThread()+"-4-"+new SimpleDateFormat("HH:mm:ss").format(new Date()));
second(5);
}
}
}
public static final void second(long seconds) {
try {
TimeUnit.SECONDS.sleep(seconds);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
结果:
Thread[WaitIng,5,main]-1-09:00:47
Thread[notifying,5,main]-3-09:00:48
Thread[notifying,5,main]-4-09:00:53
Thread[WaitIng,5,main]-2-09:00:58
细节注意:
1:使用这三个方法时需要先加锁
2:调用wait后,线程状态由runing变为waiting,并将当前线程放置到对象等待队列。
3:调用notify/notifyAll后,等待线程依旧不会从wait返回,需要待用notify的线程释放锁之后,才能从等待队列中返回。
4:从wait返回的前提是获得了调用对象的锁。
4.3.4 管道输入/输出流
PipedOutputStream,PipedInputStream,PipedReader,PipedWriter,前两种是字节,后面是字符。
4.3.5 Thread.join()的使用
如果一个线程a执行了thread.join(),含义是:当前线程a等待thread线程终止之后才从thread.join()返回,线程thread除了提供join方法之外,还提供了join(long millis)和join(long millis,int nanos)两个具备超时特性的方法。
每个线程终止的前提是前驱线程的终止,每个线程等待前驱线程终止后,才从join方法返回。
4.3.6 ThreadLocal的使用
ThreadLocal即线程变量,是一个以ThreadLocal对象为键,任意对象为值的存储结构。
4.4 线程应用
4.4.1 等待超时模式
4.4.2 数据库连接池
例子:https://gitee.com/heqiang917/study/tree/master/src/main/java/com/study/webapp/concurrency_progranmming
线程池的本质就是使用了一个线程安全的工作队列连接工作者和客户端,客户端线程将任务放入工作队列后返回,而工作者线程则不断地从工作队列上取出工作并执行,点那个工作队列为空时,所有的工作者线程均等待在工作队列中,当有客户端提交了一个任务之后会通知任意一个工作者线程,随着大量的任务被提交,更多的工作者线程会被唤醒。