一.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的原理

mark
    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