Java并发之线程基础机制、中断、互斥同步及通信协作(2)

一、基础机制

Executor

在上一篇《Java线程之状态及创建》里有提到过,Executor管理多个异步任务执行,用户无需直接进行线程的管理。在这里就不做讲解了。

Daemon Thread

jvm的GC就是一个典型的守护线程,守护线程和用户线程最大的区别在于:

1)用户线程时高优先级线程,jvm将在终止任务前等待用户线程执行完毕。

2)守护线程时低优先级线程,为用户线程提供服务。

当jvm发现没有用户线程后,守护线程会随着jvm一同结束。

声明守护线程:

    @Slf4j
    public class JunitTest {
        @Test
        public void test() throws InterruptedException {
            Thread thread = new Thread(() -> {
                System.out.println("test......");
            });
            
            // 将线程设置为守护线程
            thread.setDaemon(true);
            // 启动线程
            thread.start();
            
            Thread.sleep(3000);
        }
    }

注意:

1)thread.setDaemon(true);必须在线程调用thread.start();之前设置,否则会抛出异常IllegalThreadStateException

2)在守护线程中产生的新线程也都是守护线程。

Thread.sleep(long)

使当前正在执行的线程以指定的毫秒数暂停,线程状态进入Timed Waiting,如果该线程持有锁,则锁不释放!Object.wait()线程进入Wating状态,线程如果持有锁,则释放锁!

Thread.yield()

会告知线程调度器放弃对处理器的占用,但是调度器可以忽略这个通知,该方法主要时为了保障线程间调度的连续性,防止某个线程长期占用处理器,说白了,该方法只是对线程调度器的一个建议而且也只是建议具有相同优先级的其它线程可以运行。

二、中断

线程在运行完成后会自动结束,在发生异常后也会自动结束(程序员手动try catch异常且没有抛出此异常不会导致线程结束)。

InterruptedException

通过调用一个线程的interrupt()方法来中断这个线程,如果线程处于Timed WaitingWaiting状态,那么就会抛出InterruptedException异常,从而提前结束异常,此时线程状态为Terminated。但是不能中断IO阻塞。

interrupted()

如果一个线程的run()方法在执行一个无限循环,并且没有Thread.sleep()之类会导致线程抛出InterruptedException异常的操作,那么调用线程的inerrupted()方法无法是线程提前结束。

Executor的中断

调用Executor的shutdown()方法会在线程都执行完毕后再关闭,但是如果调用Executor的shutdownNow()方法,相当于调用每个线程的interrupt()方法。

    public static void main(String[] args) {
        ExecutorService executorService = Executors.newCachedThreadPool();
        executorService.execute(() -> {
            try {
                Thread.sleep(2000);
                System.out.println("线程aaa执行");
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        });
        executorService.shutdownNow();
        System.out.println("主线程执行完毕");
    }
    主线程执行完毕
    java.lang.InterruptedException: sleep interrupted
        at java.lang.Thread.sleep(Native Method)
        at cn.xx.xx.test.JunitTest.lambda$main$0(JunitTest.java:27)
        at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
        at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
        at java.lang.Thread.run(Thread.java:748)

上面说到了,可以使用shutdown()shutdownNow()方法来中断线程,但是这两个方法将会关闭池子里的所有线程。如果向中断某一个线程,可以使用submit()方法来提交一个线程,该方法可以返回一个Future<?>对象,调用该对象的cancel(true)可以中断线程。

    Future<?> future = executorService.submit(() -> {
        // ..
    });
    future.cancel(true);

三、互斥同步

可以参考我之前写过的一篇文章《Java 锁》

四、通信协作

2017年,记得刚刚入职现在这家公司的时候,领导给我指派了一个,开发基于销售订单销售退单及其它单据为数据蓝本,经过一系列聚合计算,得出某项数值的任务,我最终建模为四个数据存储模型,对应数据库里的四张表,简称为A、B、C、D
D数据是通过A、B、C数据计算好后通过一系列聚合计算产生的,但是A、B、C数据的计算无需互相依赖。当时上线的第一个版本采用的同步形式,即A -> B -> C -> D,计算时间大约为2~4分钟(o)后来随着学习的深入,我发现可以使用多线程进行上述计算。

过程:

创建四个线程分别对应A、B、C、D的数据计算任务,A、B、C三个任务可以同时进行,但是D数据的计算需要等待前面三个线程计算完毕才能计算,在线程D里,使用threadA.join()threadB.join()threadC.join()或者使用CountDownLatch,最后将计算时间缩短为原来的1/2,虽然这段业务代码随着后期系统重构改造消失不见~但是对我的启发是真的大。

join()

在线程中调用另外一个线程的join()方法,当前线程被挂起进入Waiting状态,直到被调用线程执行完毕。

Object - wait()、notify()、notifyAll()

调用wait()方法,会使线程挂起进入Waiting状态,其它线程可以使用notify()notifyAll()方法将这个线程唤醒,这三种方法都是属于Object的方法。而且这三个方法只能在被synchronized修饰的方法和代码块中执行,否则抛出IllegalMonitorStateException异常。
在调用wait()方法后,线程被挂起,锁被交出,如果不交出锁,也不可能有其它线程进入方法或者代码块来唤醒这个线程,岂不就是死锁了?

在使用synchronized关键字时,配合使用Object的wait()notify()notifyAll()方法达到线程间通信协作的目的。

Condition - await()、awaitNanos(long)、awaitUntil(Date)、awaitUninterruptibly()、signal()、signalAll()

Condition Java 1.5 才出的,用以配合使用Lock锁时的线程间通信协作,Condition必须要Lock实现类去创建。
而且Condition的await指定等待的条件,更加的灵活。

    @Slf4j
    public class JunitTest {
        ReentrantLock lock = new ReentrantLock();
    
        Condition condition = lock.newCondition();

        @Test
        public void test() throws InterruptedException {
            Thread thread1 = new Thread(() -> {
                lock.lock();
                try {
                    log.info("线程1启动,但是需要等待线程2通知,我先休息休息");
                    condition.await();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                log.info("线程2通知我干活了,去打扫战场喽~");
    
                lock.unlock();
            });
    
            Thread thread2 = new Thread(() -> {
                lock.lock();
                log.info("线程2启动,开始做任务刷副本~");
                log.info("副本做完了,准备通知线程1打扫战场,我先休息休息");
                condition.signal();
                log.info("通知线程1完毕");
                lock.unlock();
            });
    
            thread1.start();
    
            Thread.sleep(2000);
    
            thread2.start();
    
            Thread.sleep(10000);
        }
    }
    16:12:40.661 [Thread-0] INFO  cn.xx.x.test.JunitTest - 线程1启动,但是需要等待线程2通知,我先休息休息
    16:12:42.660 [Thread-1] INFO  cn.xx.x.test.JunitTest - 线程2启动,开始做任务刷副本~
    16:12:42.660 [Thread-1] INFO  cn.xx.x.test.JunitTest - 副本做完了,准备通知线程1打扫战场,我先休息休息
    16:12:42.660 [Thread-1] INFO  cn.xx.x.test.JunitTest - 通知线程1完毕
    16:12:42.661 [Thread-0] INFO  cn.xx.x.test.JunitTest - 线程2通知我干活了,去打扫战场喽~
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,324评论 5 476
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,303评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,192评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,555评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,569评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,566评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,927评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,583评论 0 257
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,827评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,590评论 2 320
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,669评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,365评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,941评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,928评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,159评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,880评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,399评论 2 342