龙空技术网

JUC(一)--天下内功正宗

隐形喷火龙 399

前言:

此时姐妹们对“java内功”大体比较着重,小伙伴们都想要学习一些“java内功”的相关知识。那么小编同时在网上收集了一些有关“java内功””的相关知识,希望你们能喜欢,各位老铁们快快来了解一下吧!

《射雕英雄传》里有这么个桥段,郭靖自拜江南七怪为师后,刻苦练功,从不懈怠,但是进展缓慢,弄的江南七怪都心灰意冷,觉得他不是练武的材料。后来,全真派掌门丹阳子马钰得知丘处机和江南七怪的赌约,对江南七怪心生敬重,于是特地来到蒙古,在悬崖绝顶教授郭靖全真派内功足足两年,郭靖内功不仅大有长进,练起江南七怪教授的武功也得心应手起来。

全真派内功被誉为天下内功正宗,进境虽慢,却绝不出岔子。而JUC就是如此,JUC是高并发的基石,学好了JUC,就是打好了内功根基,再学习高并发相关知识就有了理论基础。接下来我们聊聊JUC那些事儿。

JUC就是java.util .concurrent工具包的简称,专门用来处理多线程相关问题的。

什么是进程和线程

进程是程序的⼀次执⾏,是系统进⾏资源分配和调度的独⽴单位,每⼀个进程都有它⾃⼰的内存空间和系统资源

在同⼀个进程内⼜可以执⾏多个任务,⽽这每⼀个任务我们就可以看做是⼀个线程

创建线程的三种方式

public void startThead() throws ExecutionException, InterruptedException {    //方式一,继承自thread,不推荐    new Thread() {        @Override        public void run() {            log.info("方式1执行");        }    }.start();    //方式二,实现Runnable接口,业务与线程分离    new Thread(new Runnable() {        @Override        public void run() {            log.info("方式二执行");        }    }).start();    //方式三,使用FutureTask,可以获得线程执行结果    FutureTask<Long> task = new FutureTask<>(new Callable<Long>() {        @Override        public Long call() throws Exception {            Thread.sleep(1000);            return 100L;        }    });    new Thread(task).start();    //获取线程执行结果,处于阻塞状态    log.info(task.get() + "");}

打断线程(interrupt)

很多人对interrupt方法有个误解,以为调用这个方法后线程就不会执行了,其实interrupt方法只会设置打断标记,不会终止线程的执行。如果被打断线程处于sleep,wait,join则会抛出InterruptedException.

sleep情况下被打断,会终止睡眠并抛InterruptedException

public void testInterrupt() throws InterruptedException {    Thread thread = new Thread(new Runnable() {        @Override        public void run() {            try {                Thread.sleep(5000);            } catch (InterruptedException e) {                //调用interrupt后会抛InterruptedException异常                log.info("被打断");            }            log.info("还能继续执行");        }    });    thread.start();    TimeUnit.SECONDS.sleep(1);    thread.interrupt();}

正常运行的情况下被打断

public void testInterrupt() throws InterruptedException {    Thread thread = new Thread(() -> {        while (true) {            log.info("正在执行");            if (Thread.currentThread().isInterrupted()) {                log.info("interrupt方法会让打断标志为true,手动退出");                break;            }        }    });    thread.start();    TimeUnit.SECONDS.sleep(1);    thread.interrupt();}

优雅的终止线程

thread里面有个stop方法可以停止线程,但这个方法不会释放锁,而且该方法已经过时了,永远不要靠调这个方法来终止线程。

我们来看个经典的两阶段终止模式

public void testInterrupt() throws InterruptedException {    Thread thread = new Thread(() -> {        while (true) {            if (Thread.currentThread().isInterrupted()) {                log.info("线程终止,释放资源");                break;            }            log.info("执行监控");            try {                //睡眠1S                TimeUnit.SECONDS.sleep(1);            } catch (InterruptedException e) {                log.info("sleep的时候被打断会清除打断标志,需要重新设置");                Thread.currentThread().interrupt();            }        }    });    thread.start();    TimeUnit.SECONDS.sleep(5);    thread.interrupt();}

输出如下:

17:05:02.106 [Thread-0] INFO com.wkt.ThreadTest - 执行监控17:05:03.119 [Thread-0] INFO com.wkt.ThreadTest - 执行监控17:05:04.119 [Thread-0] INFO com.wkt.ThreadTest - 执行监控17:05:05.125 [Thread-0] INFO com.wkt.ThreadTest - 执行监控17:05:06.138 [Thread-0] INFO com.wkt.ThreadTest - 执行监控17:05:07.102 [Thread-0] INFO com.wkt.ThreadTest - sleep的时候被打断不会设置标志位,需要自己设置17:05:07.102 [Thread-0] INFO com.wkt.ThreadTest - 线程终止,释放资源

用户线程与守护线程

Java线程分为用户线程(主线程)和守护线程,线程的daemon属性为true表示是守护线程,false表示是用户线程。

用户线程是系统的工作线程,它会完成这个程序需要完成的业务操作。

守护线程是一种特殊的线程,在后台默默地完成一些系统性的服务,比如垃圾回收线程。守护线程会在主线程退出后自动终止。设置守护线程,需要在start()方法之前进行

当程序中所有用户线程执行完毕之后,不管守护线程是否结束,系统都会自动退出

标签: #java内功