一.Thred.join的使用及原理
Thred.join的作用是保证线程执行结果的可见性
1.Thread.join的使用
public class ThreadJoinDemo {
private static int x = 0;
private static int y = 0;
public static void main(String[] args) {
Thread t1 = new Thread(() -> {
x = 1;
y = 2;
});
Thread t2 = new Thread(() -> {
x = y + 2;
});
t1.start();
t2.start();
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("Result:" + x);
多次运行上段代码,因为t1和t2的运行顺序不同,所以运行结果会有两种情况: Result:1 Result:4
public class ThreadJoinDemo {
private static int x = 0;
private static int y = 0;
public static void main(String[] args) throws InterruptedException {
Thread t1 = new Thread(() -> {
x = 1;
y = 2;
});
Thread t2 = new Thread(() -> {
x = y + 2;
});
t1.start();
//保证t1线程的执行结果对于t2可见 使t1一定比t2优先进行
//主线程处于阻塞状态 t1执行完毕退出后主线程被唤醒
t1.join();
t2.start();
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("Result:" + x);
}
}
此时无论运行多少次运行结果均为Result:4
2.Thread.join的原理

public final synchronized void join(long millis)
throws InterruptedException {
long base = System.currentTimeMillis();
long now = 0;
if (millis < 0) {
throw new IllegalArgumentException("timeout value is negative");
}
if (millis == 0) {
//核心代码 如果当前线程处于存活状态 则使主线程阻塞
while (isAlive()) {
wait(0);
}
} else {
while (isAlive()) {
long delay = millis - now;
if (delay <= 0) {
break;
}
wait(delay);
now = System.currentTimeMillis() - base;
}
}
}
3.Thread.join的本质
thread.join的本质其实是wait/notifyall
二.Thread.sleep的使用和原理
使得线程暂停执行一段时间,知道等待的时间结束恢复执行或期间被中断
Thread.sleep的使用
public class ThreadSleepDemo extends Thread {
@Override
public void run() {
System.out.println("begin"+System.currentTimeMillis());
try {
Thread.sleep(300);//睡眠3秒 单位毫秒
System.out.println("end"+System.currentTimeMillis());
} catch (InterruptedException e) {
e.printStackTrace();
}
}
public static void main(String[] args) {
new ThreadSleepDemo().start();
}
}
begin1585581083522
end1585581083822
Thread.sleep的工作流程
1.挂起线程并修改其运行状态
2.用sleep()提供的参数来设置一个定时器
3.当时间结束,定时器会触发,内核收到中断后修改线程的运行状态(例如线程会被标志为就绪而进入就绪队列等待调度)
使用Thread.sleep(0) 线程会告诉CPU在接下来的0毫秒内不参与线程的竞争,促使CPU重新分配线程.
三.wait和notify的使用
wait 休眠线程 notify 唤醒线程
实现代码:
public class Consumer implements Runnable{
private Queue<String> bags;
private int size;
public Consumer(Queue<String> bags, int size) {
this.bags = bags;
this.size = size;
}
@Override
public void run() {
while(true){
synchronized (bags){
while(bags.isEmpty()){
System.out.println("bags为空");
try {
bags.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
String bag=bags.remove();
System.out.println("消费者消费:"+bag);
bags.notifyAll();
}
}
}
}
public class Producer implements Runnable{
private Queue<String> bags;
private int size;
public Producer(Queue<String> bags, int size) {
this.bags = bags;
this.size = size;
}
@Override
public void run() {
int i=0;
while(true){
i++;
synchronized (bags){
while(bags.size()==size){
System.out.println("bags已经满了");
//TODO? 阻塞?
try {
bags.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("生产者-生产:bag"+i);
bags.add("bag"+i);
//TODO? 唤醒处于阻塞状态下的消费者
bags.notifyAll();
}
}
}
}
public class ThreadWaitAndNotifyDemo {
public static void main(String[] args) {
Queue<String> queue = new LinkedList<>();
int size = 10;
Producer producer = new Producer(queue,size);
Consumer consumer = new Consumer(queue,size);
Thread t1 = new Thread(producer);
Thread t2 = new Thread(consumer);
t1.start();
t2.start();
}
}
wait/notyfy需要加synchronized修饰,wait/notyfy本质上其实一种条件的竞争,互斥存在,要实现互斥,可以使用synchronized.
wait/notyfy用于实现多个线程之间的通信.
Thread.interrupted和Thread.interrupt
其他线程通过调用当前线程的interrupt方法,表示当前线程可以中断执行,具体中断取决于线程自己
终止线程的一种方式
public class stopDemo {
//通过共享变量控制线程结束
private static boolean stop = false;
public static void main(String[] args) throws InterruptedException {
Thread t1 = new Thread(new StopThread());
t1.start();
//t1.stop();属于强制终止
//休眠两秒 然后设置sop为true
TimeUnit.SECONDS.sleep(2);
stop = true;
}
static class StopThread implements Runnable{
@Override
public void run() {
while (!stop){
System.out.println("持续运行");
try {
//睡眠一秒
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
}
interrupt方法的一种使用
public class InterruptDemo {
private static int i;
public static void main(String[] args) {
Thread thread = new Thread(()->{
//Thread.currentThread().isInterrupted()默认是false
while (!Thread.currentThread().isInterrupted()){
i++;
}
});
thread.start();
//将false改变为true
thread.interrupt();
}
}
当线程处于阻塞、死循环时interrupt的使用
/**
* 线程结束意味着run方法执行完毕
* 当线程处于阻塞状态 无法终止时 可以调用interrupt方法
* 线程会从阻塞状态唤醒并抛出InterruptedException异常
* 然后结束当前的线程
* @param args
*/
public static void main(String[] args) {
Thread thread = new Thread(()->{
try {
Thread.sleep(100000);
} catch (InterruptedException e) {
e.printStackTrace();
}
});
thread.start();
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
thread.interrupt();
}
java.lang.InterruptedException: sleep interrupted
at java.lang.Thread.sleep(Native Method)
at com.yzf.demo.demo.Thread.InterruptDemo.lambda$main$0(InterruptDemo.java:33)
at java.lang.Thread.run(Thread.java:748)
interrupted方法的使用
Thread.interrupted方法对设置中断标识的线程复位,并返回当前的中断状态
public class InterruptedDemo {
private static int i;
public static void main(String[] args) throws InterruptedException {
Thread thread = new Thread(() -> {
while (true) {
//true标识被其他线程中断过
if (Thread.currentThread().isInterrupted()){
System.out.println("before:"+Thread.currentThread().isInterrupted());
Thread.interrupted();//将中断标识符复位为false
System.out.println("after:"+Thread.currentThread().isInterrupted());
}
}
});
thread.start();
TimeUnit.SECONDS.sleep(1);
thread.interrupt();//中断
}
}
before:true
after:false
退出登录?