23.01 线程间的等待唤醒机制
A:wait()
Object类中,void wait() 在其他线程调用此对象的 notify() 方法或
notifyAll() 方法前,导致当前线程等待。
void wait(long timeout) 在其他线程调用此对象的 notify() 方法或
notifyAll() 方法,或者超过指定的时间量前,导致当前线程等待。
void notify() 唤醒在此对象监视器上等待的单个线程。
void notifyAll() 唤醒在此对象监视器上等待的所有线程。
public class Demo01wait {
public static void main ( String[ ] args) {
Student student = new Student ( ) ;
SetThread st = new SetThread ( student) ;
GetThread gt = new GetThread ( student) ;
st. start ( ) ;
gt. start ( ) ;
}
}
public class Student {
public String name;
public int age;
public boolean flag = false ;
}
public class SetThread extends Thread {
private Student student;
int i = 0 ;
public SetThread ( Student student) {
this . student = student;
}
@Override
public void run ( ) {
while ( true ) {
synchronized ( student) {
if ( student. flag) {
try {
student. wait ( ) ;
} catch ( InterruptedException e) {
e. printStackTrace ( ) ;
}
}
if ( i% 2 == 0 ) {
student. name = "张三" ;
student. age = 23 ;
} else {
student. name = "李四" ;
student. age = 24 ;
}
student. flag = true ;
student. notify ( ) ;
}
i++ ;
}
}
}
public class GetThread extends Thread {
private Student student;
public GetThread ( Student student) {
this . student = student;
}
@Override
public void run ( ) {
while ( true ) {
synchronized ( student) {
if ( ! student. flag) {
try {
student. wait ( ) ;
} catch ( InterruptedException e) {
e. printStackTrace ( ) ;
}
}
System. out. println ( student. name + "====" + student. age) ;
student. flag = false ;
student. notify ( ) ;
}
}
}
}
23.02 内存可见性问题 volatile
A:volatile 关键字:
当多个线程进行操作共享数据时,可以保证内存中的数据可见。相较于
synchronized 是一种较为轻量级的同步策略。
B:volatile 变量,用来确保将变量的更新操作通知到其他线程。可以将
volatile 看做一个轻量级的锁,但是又与锁有些不同:
对于多线程,不是一种互斥关系
不能保证变量状态的 “原子性操作”。
public class Demo01Volatile {
public static void main ( String[ ] args) {
MyRunnable mr = new MyRunnable ( ) ;
Thread thread = new Thread ( mr) ;
thread. start ( ) ;
while ( true ) {
if ( mr. isFlag ( ) ) {
System. out. println ( "进来了" ) ;
break ;
}
}
}
}
class MyRunnable implements Runnable {
volatile boolean flag = false ;
public boolean isFlag ( ) {
return flag;
}
public void setFlag ( boolean flag) {
this . flag = flag;
}
@Override
public void run ( ) {
try {
Thread. sleep ( 50 ) ;
} catch ( InterruptedException e) {
e. printStackTrace ( ) ;
}
flag = true ;
System. out. println ( flag) ;
}
}
23.03 CAS算法
A:CAS算法
CAS(Compare-And-Swap) 是一种硬件对并发的支持,针对多处理器操作而
设计的处理器中的一种特殊指令,用于管理对共享数据的并发访问
CAS是一种无锁的非阻塞算法的实现。
CAS包含了 3 个操作数:
需要读写的内存值 V
进行比较的值 A
拟写入的新值 B
当且仅当 V 的值等于 A 时,CAS 通过原子方式用新值 B 来更新 V 的值,
否则不会执行任何操作。
java.util.concurrent.atomic 包下提供了一些原子操作的常用类:
AtomicBoolean、AtomicInteger、AtomicLong、AtomicReference
AtomicIntegerArray、AtomicLongArray
AtomicMarkableReference
AtomicReferenceArray
public class Demo01Cas {
public static void main ( String[ ] args) {
MyRunnable mr = new MyRunnable ( ) ;
for ( int i = 0 ; i < 10 ; i++ ) {
new Thread ( mr) . start ( ) ;
}
}
}
class MyRunnable implements Runnable {
AtomicInteger i = new AtomicInteger ( 1 ) ;
public AtomicInteger getI ( ) {
return i;
}
@Override
public void run ( ) {
while ( true ) {
synchronized ( MyRunnable. class ) {
try {
Thread. sleep ( 50 ) ;
} catch ( InterruptedException e) {
e. printStackTrace ( ) ;
}
System. out. println ( i. getAndIncrement ( ) ) ;
}
}
}
}
23.04 线程状态的常见执行情况
A:新建,就绪,运行,冻结,死亡
新建:线程被创建出来
就绪:具有CPU的执行资格,但是不具有CPU的执行权
运行:具有CPU的执行资格,也具有CPU的执行权
阻塞:不具有CPU的执行资格,也不具有CPU的执行权
死亡:不具有CPU的执行资格,也不具有CPU的执行权
23.05 线程池
A:线程池的意义
线程池主要用来解决线程生命周期开销问题和资源不足问题。通过对多个
任务重复使用线程,线程创建的开销就被分摊到了多个任务上了,而且由
于在请求到达时线程已经存在,所以消除了线程创建所带来的延迟。这样
就可以立即为请求服务,使用应用程序响应更快。另外,通过适当的调整
线程中的线程数目可以防止出现资源不足的情况。
B:线程池的组成部分
至少应包含线程池管理器、工作线程、任务队列、任务接口等部分。其中
线程池管理器的作用是创建、销毁并管理线程池,将工作线程放入线程池
中;工作线程是一个可以循环执行任务的线程,在没有任务时进行等待;
任务队列的作用是提供一种缓冲机制,将没有处理的任务放在任务队列中;
任务接口是每个任务必须实现的接口,主要用来规定任务的入口、任务执
行完后线程池管理器至少有下列功能:创建线程池、销毁线程池、添加新
任务。
C:内置线程的使用
public static ExecutorService newCachedThreadPool():
根据任务的数量来创建线程对应的线程个数
public static ExecutorService newFixedThreadPool():
固定初始化几个线程
public static ExecutorService newSingleThreadExecutor():
初始化一个线程的线程池
这些方法的返回值是 ExecutorService 对象,该对象表示一个线程池,
可以执行 Runnable 对象或者 Callable 对象代表的线程。
Future<?> submit(Runnable task)
<T> Future<T> submit(Callable<T> task)
public static void main ( String[ ] args) {
ExecutorService es = Executors. newCachedThreadPool ( ) ;
es. submit ( new Runnable ( ) {
@Override
public void run ( ) {
System. out. println ( Thread. currentThread ( ) . getName ( ) + "执行了111111" ) ;
}
} ) ;
es. submit ( new Runnable ( ) {
@Override
public void run ( ) {
System. out. println ( Thread. currentThread ( ) . getName ( ) + "执行了222222" ) ;
}
} ) ;
es. submit ( new Runnable ( ) {
@Override
public void run ( ) {
System. out. println ( Thread. currentThread ( ) . getName ( ) + "执行了333333" ) ;
}
} ) ;
es. shutdown ( ) ;
}
public static void main ( String[ ] args) throws ExecutionException, InterruptedException {
ExecutorService es = Executors. newFixedThreadPool ( 3 ) ;
Future< Integer> future = es. submit ( new Callable < Integer> ( ) {
@Override
public Integer call ( ) throws Exception {
System. out. println ( "执行了" ) ;
return 100 ;
}
} ) ;
Integer integer = future. get ( ) ;
System. out. println ( integer) ;
}
public static void main ( String[ ] args) {
ExecutorService es = Executors. newSingleThreadExecutor ( ) ;
es. submit ( new Runnable ( ) {
@Override
public void run ( ) {
System. out. println ( Thread. currentThread ( ) . getName ( ) + "执行了111111" ) ;
}
} ) ;
es. submit ( new Runnable ( ) {
@Override
public void run ( ) {
System. out. println ( Thread. currentThread ( ) . getName ( ) + "执行了222222" ) ;
}
} ) ;
es. submit ( new Runnable ( ) {
@Override
public void run ( ) {
System. out. println ( Thread. currentThread ( ) . getName ( ) + "执行了333333" ) ;
}
} ) ;
}
public static void main ( String[ ] args) {
ThreadPoolExecutor tpe = new ThreadPoolExecutor ( 3 , 10 , 10 L, TimeUnit. SECONDS,
new ArrayBlockingQueue < > ( 1000 ) , Executors. defaultThreadFactory ( ) ,
new ThreadPoolExecutor. AbortPolicy ( ) ) ;
tpe. execute ( new Runnable ( ) {
@Override
public void run ( ) {
System. out. println ( "任务执行完了" ) ;
}
} ) ;
tpe. shutdown ( ) ;
}
23.06 定时器
A:定时器概述
定时器是一个应用十分广泛的线程工具,可用于调度多个定时任务以后台
线程的方式执行。在Java中,可以通过 Timer 和 TimerTask 类来实现
定义调度的功能。
B:Timer 和 TimerTask
Timer:
public Timer()
public void schedule(TimerTask task, long delay)
public void schedule(TimerTask task, long delay, long period)
public void schedule(TimerTask task, Date time)
public void schedule(TimerTask task, Date firstTime, long period)
TimerTask:定时任务
public abstract void run()
public boolean cancel()
public class Demo01Timer {
public static void main ( String[ ] args) {
Timer timer = new Timer ( ) ;
MyTimerTask mtt = new MyTimerTask ( timer) ;
timer. schedule ( mtt, 1000 * 5 ) ;
}
}
class MyTimerTask extends TimerTask {
private Timer timer;
public MyTimerTask ( Timer timer) {
this . timer = timer;
}
@Override
public void run ( ) {
System. out. println ( "砰~~~爆炸了" ) ;
timer. cancel ( ) ;
}
}
public static void main ( String[ ] args) {
Timer timer = new Timer ( ) ;
timer. schedule ( new TimerTask ( ) {
@Override
public void run ( ) {
System. out. println ( "砰~~~爆炸了" ) ;
}
} , 1000 * 2 , 1000 ) ;
}
public static void main ( String[ ] args) throws ParseException {
Timer timer = new Timer ( ) ;
String dateStr = "2021-06-07 20:25:00" ;
Date date = new SimpleDateFormat ( "yyyy-MM-dd HH:mm:ss" ) . parse ( dateStr) ;
timer. schedule ( new TimerTask ( ) {
@Override
public void run ( ) {
System. out. println ( "发送邮件" ) ;
}
} , date) ;
}
public static void main ( String[ ] args) throws ParseException {
Timer timer = new Timer ( ) ;
String dateStr = "2021-06-07 20:28:00" ;
Date date = new SimpleDateFormat ( "yyyy-MM-dd HH:mm:ss" ) . parse ( dateStr) ;
timer. schedule ( new TimerTask ( ) {
@Override
public void run ( ) {
System. out. println ( "发送邮件" ) ;
}
} , date, 1000 ) ;
}