操作系统的并发控制
信号量与P-V原语
互斥量
自旋锁
读写锁
中断控制与内核抢占
顺序锁
rcu锁
JAVA启动线程的5种方法
- new MyThread().start()
- new Thread®.start()
- new Thread(lamda).start()
- ThreadPool
- Future Callable and FutureTask
常见的线程方法
我们来认识几个线程的方法
sleep() yield() join()
package com.mashibing.juc.c_000;
public class T03_Sleep_Yield_Join {
public static void main(String[] args) {
//testSleep();
//testYield();
testJoin();
}
/*Sleep,意思就是睡眠,当前线程暂停一段时间让给别的线程去运行。Sleep是怎么复活的?由你的睡眠时间而定,等睡眠到规定的时间自动复活*/
static void testSleep() {
new Thread(()->{
for(int i=0; i<100; i++) {
System.out.println("A" + i);
try {
Thread.sleep(500);
//TimeUnit.Milliseconds.sleep(500)
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}).start();
}
/*Yield,就是当前线程正在执行的时候停止下来进入等待队列(就绪状态,CPU依然有可能把这个线程拿出来运行),回到等待队列里在系统的调度算法里头呢还是依然有可能把你刚回去的这个线程拿回来继续执行,当然,更大的可能性是把原来等待的那些拿出一个来执行,所以yield的意思是我让出一下CPU,后面你们能不能抢到那我不管*/
static void testYield() {
new Thread(()->{
for(int i=0; i<100; i++) {
System.out.println("A" + i);
if(i%10 == 0) Thread.yield();
}
}).start();
new Thread(()->{
for(int i=0; i<100; i++) {
System.out.println("------------B" + i);
if(i%10 == 0) Thread.yield();
}
}).start();
}
/*join, 意思就是在自己当前线程加入你调用Join的线程(),本线程等待。等调用的线程运行完了,自己再去执行。t1和t2两个线程,在t1的某个点上调用了t2.join,它会跑到t2去运行,t1等待t2运行完毕继续t1运行(自己join自己没有意义) */
static void testJoin() {
Thread t1 = new Thread(()->{
for(int i=0; i<100; i++) {
System.out.println("A" + i);
try {
Thread.sleep(500);
//TimeUnit.Milliseconds.sleep(500)
} catch (InterruptedException e) {
e.printStackTrace();
}
}
});
Thread t2 = new Thread(()->{
try {
t1.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
for(int i=0; i<100; i++) {
System.out.println("A" + i);
try {
Thread.sleep(500);
//TimeUnit.Milliseconds.sleep(500)
} catch (InterruptedException e) {
e.printStackTrace();
}
}
});
t1.start();
t2.start();
}
}
线程状态
小节说明:
- 本节重要程度:中 (帮助理解线程问题,保障知识完整性,面试很少考)
- 本节难度:低
JAVA的6中线程状态:
- NEW : 线程刚刚创建,还没有启动
- RUNNABLE : 可运行状态,由线程调度器可以安排执行
- 包括READY和RUNNING两种细分状态
- WAITING: 等待被唤醒
- TIMED WAITING: 隔一段时间后自动唤醒
- BLOCKED: 被阻塞,正在等待锁
- TERMINATED: 线程结束
如下图:
线程状态测试代码:
package com.mashibing.juc.c_000_threadbasic;
import com.mashibing.util.SleepHelper;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.LockSupport;
/**
* title:${file_name}
* 关于线程状态的实验
* @author 马士兵 http://www.mashibing.com
* @date ${date}
* @version 2.0
*/
public class T04_ThreadState {
static class MyThread extends Thread {
@Override
public void run() {
System.out.println("2: " + this.getState());
for (int i = 0; i < 10; i++) {
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.print(i + " ");
}
System.out.println();
}
}
public static void main(String[] args) throws Exception {
Thread t1 = new MyThread();
System.out.println("1: " + t1.getState());
t1.start();
t1.join();
System.out.println("3: " + t1.getState());
Thread t2 = new Thread(() -> {
try {
LockSupport.park();
System.out.println("t2 go on!");
TimeUnit.SECONDS.sleep(5);
} catch (InterruptedException e) {
e.printStackTrace();
}
});
t2.start();
TimeUnit.SECONDS.sleep(1);
System.out.println("4: " + t2.getState());
LockSupport.unpark(t2);
TimeUnit.SECONDS.sleep(1);
System.out.println("5: " + t2.getState());
final Object o = new Object();
Thread t3 = new Thread(()->{
synchronized (o) {
System.out.println("t3 得到了锁 o");
}
});
new Thread(()-> {
synchronized (o) {
SleepHelper.sleepSeconds(5);
}
}).start();
SleepHelper.sleepSeconds(1);
t3.start();
SleepHelper.sleepSeconds(1);
System.out.println("6: " + t3.getState());
}
}
线程的打断
小节说明:
重要程度:中(面试不多)
小节难度:低
interrupt相关的三个方法:
//Thread.java
public void interrupt() //t.interrupt() 打断t线程(设置t线程某给标志位f=true,并不是打断线程的运行)
public boolean isInterrupted() //t.isInterrupted() 查询打断标志位是否被设置(是不是曾经被打断过)
public static boolean interrupted()//Thread.interrupted() 查看“当前”线程是否被打断,如果被打断,恢复标志位
- interrupt() :实例方法,设置线程中断标志(打扰一下,你该处理一下中断)
- isInterrupted():实例方法,有没有人打扰我?
- interrupted():静态方法,有没有人打扰我(当前线程)?复位!
interrupt和sleep() wait() join()
sleep()方法在睡眠的时候,不到时间是没有办法叫醒的,这个时候可以用interrupt设置标志位,然后呢必须得catch InterruptedException来进行处理,决定继续睡或者是别的逻辑,(自动进行中断标志复位)
interrupt是否能中断正在竞争锁的线程
package com.mashibing.juc.c_000_threadbasic;
import com.mashibing.util.SleepHelper;
/**
* interrupt与sleep() wait() join()
*/
public class T09_Interrupt_and_sync {
private static Object o = new Object();
public static void main(String[] args) {
Thread t1 = new Thread(()-> {
synchronized (o) {
SleepHelper.sleepSeconds(10);
}
});
t1.start();
SleepHelper.sleepSeconds(1);
Thread t2 = new Thread(()-> {
synchronized (o) {
}
System.out.println("t2 end!");
});
t2.start();
t2.interrupt();
}
}
interrupt()不能打断正在竞争锁的线程synchronized()
如果想打断正在竞争锁的线程,使用ReentrantLock的lockInterruptibly()
package com.mashibing.juc.c_000_threadbasic;
import com.mashibing.util.SleepHelper;
import java.util.concurrent.locks.ReentrantLock;
/**
* interrupt与lockInterruptibly()
*/
public class T11_Interrupt_and_lockInterruptibly {
private static ReentrantLock lock = new ReentrantLock();
public static void main(String[] args) {
Thread t1 = new Thread(()-> {
lock.lock();
try {
SleepHelper.sleepSeconds(10);
} finally {
lock.unlock();
}
System.out.println("t1 end!");
});
t1.start();
SleepHelper.sleepSeconds(1);
Thread t2 = new Thread(()-> {
System.out.println("t2 start!");
try {
lock.lockInterruptibly();
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
lock.unlock();
}
System.out.println("t2 end!");
});
t2.start();
SleepHelper.sleepSeconds(1);
t2.interrupt();
}
}
优雅的结束线程
小节说明:
本节内容的重要程度:中(面试有可能被问)
小节难度:低
结束线程的方法:
- 自然结束(能自然结束就尽量自然结束)
- stop() suspend() resume()
- volatile标志
- 不适合某些场景(比如还没有同步的时候,线程做了阻塞操作,没有办法循环回去)
- 打断时间也不是特别精确,比如一个阻塞容器,容量为5的时候结束生产者,
但是,由于volatile同步线程标志位的时间控制不是很精确,有可能生产者还继续生产一段儿时间
- interrupt() and isInterrupted(比较优雅)
线程组
(不重要,暂忽略。)
ThreadGroups - Thread groups are best viewed as an unsuccessful experiment , and you may simply ignore their existence! - Joshua Bloch one of JDK designers