博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Thread API的详细介绍
阅读量:5243 次
发布时间:2019-06-14

本文共 15828 字,大约阅读时间需要 52 分钟。

import java.util.ArrayList;import java.util.Arrays;import java.util.List;import java.util.concurrent.ThreadLocalRandom;import java.util.concurrent.TimeUnit;import java.util.stream.IntStream;import static java.util.stream.Collectors.toList;public class Test {    public static void main(String[] args){//        ThradSleep.test();//        ThreadPriority.test();//        ThreadPriority.test();//        ThreadId.test();//        CurrentThread.test();//        ThreadInterrupt.test();//        ThreadIsInterrupted.test();//        ThreadIsInterrupted2.test();//        ThreadInterrupted.test();//        ThreadTest.test();//        ThreadJoin.test();//        FightQueryExample.test();        FlagThreadExit.test();`    }}/*    3.1.1 sleep方法介绍        public static void sleep(long millis) throws InterruptedException        public static void sleep(long millis, int nanos) throws InterruptedException    3.1.2 使用TimeUnit代替Thread.sleep        TimeUnit可以省去换算的步骤,比如线程想休眠3小时24分17秒88毫秒:            TimeUnit.HOURS.sleep(3);            TimeUnit.MINUTES.sleep(3);            TimeUnit.SECONDS.sleep(3);            TimeUnit.MILLISECONDS.sleep(3);            ——我是真的需要把Java枚举部分看一下了。。。 */class ThradSleep{    public static void test(){        new Thread(()->{            long startTime=System.currentTimeMillis();            sleep(2_000L);            long endTime=System.currentTimeMillis();            System.out.println("Total: "+(endTime-startTime));        }).start();        long startTime=System.currentTimeMillis();        sleep(3_000L);        long endTime=System.currentTimeMillis();        System.out.println("Main Total: "+(endTime-startTime));    }    private static void sleep(long ms){        try{            Thread.sleep(ms);        } catch (InterruptedException e) {            e.printStackTrace();        }    }}/*    3.2.1 yield方法介绍    调用yield方法会使当前线程从RUNNING状态切换到RUNNABLE状态,这个方法一般不常用        ——Java8的流和Lam,早看早练习,稳赚不赔!!!    3.2.2 yield和sleep    其本质区别:        1.sleep会导致当前线程暂停指定的之间,没有CPU时间片的消耗。(这个CPU时间片消耗指的是什么?)        2.yield只是对CPU调度器的一个暗示,可能导致线程上下文的切换。        3.sleep会使线程短暂block,会在指定的时间内释放CPU资源        4.yield会使RUNNING状态的Thread进入RUNABLE状态        5.sleep几乎会百分百地完成指定时间的休眠,而yield的提示并不一定有用        6.一个线程内调用了sleep,另一个线程调用了interrupt,这个调用了sleep的线程会捕获到        中断信号,而yield不会。 */class ThreadYield{    public static void test() {        IntStream.range(0,2).mapToObj(ThreadYield::create)                .forEach(Thread::start);    }    private static Thread create(int index) {        return new Thread(()->{            if (index == 0) {                Thread.yield();            }            System.out.println(index);        });    }}/*    3.3 设置线程优先级        public final void setPriority(int newPriority); :为线程设定优先级        public final int getPriority();                 :获得线程的优先级    3.3.2 线程优先级源码分析    要点:        1.线程的优先级不能小于1,不能大于10;        2.如果优先级大于group的优先级,则优先级会被设置为group的优先级; */class ThreadPriority{    public static void test(){        /* 实验设置优先级        Thread t1 = new Thread(()->{            while(true){                System.out.println("t1");            }        });        Thread t2 = new Thread(()->{            while(true){                System.out.println("t1");            }        });        t1.setPriority(3);        t2.setPriority(10);        t1.start();        t2.start();        */        /* 实验线程优先级和组优先级关系        ThreadGroup group = new ThreadGroup("test");        group.setMaxPriority(7);        Thread t = new Thread(group,"test-thread");        t.setPriority(10);        System.out.println("t.getPriority():"+t.getPriority());        */        /* 实验线程默认优先级 */        Thread t1 = new Thread();        System.out.println("t1 priority:"+t1.getPriority());        Thread t2 = new Thread(()->{            Thread t3 = new Thread();            System.out.println("t3 priority:"+t3.getPriority());        });        t2.setPriority(6);        t2.start();        System.out.println("t2 priority:"+t2.getPriority());    }}/*    3.4 获取线程ID        public long getId(); */class ThreadId{    public static void test(){        System.out.println("main id: "+Thread.currentThread().getId());        Thread t = new Thread("test");        System.out.println("t id: "+t.getId());    }}/*    3.5 获取当前线程        public static Thread currentThread(); */class CurrentThread{    public static void test(){        Thread t = new Thread() {            public void run() {                System.out.println(Thread.currentThread() == this);            }        };        t.start();        String name = Thread.currentThread().getName();        System.out.println("main".equals(name));    }}/*    3.6 设置线程上下文类加载器        public ClassLoader getContextClassLoader()        :获取        public void setContextClassLoader(ClassLoader cl) :设置 *//* ************************************************************************* ************************************************************************* ************************************************************************* ************************************************************************* *//*    3.7 线程interrupt        public void interrupt()        public static boolean interrupted()        public boolean isInterrupted()        ——标记一下,我对interrupted()方法有点疑惑,这个方法是怎么办到把我一个            对象的标识位给复原了的。额,很尴尬,它调用了一个currentThread方法,            然后间接的设置了这个标志位,也就说明这个方法只能在某个Thread内部调用。    3.7.1 interrupt    如下方法的调用会使得当前线程进入阻塞状态:        1.Object的wait(),wait(long),wait(long,int)        2.Thread的sleep(long),sleep(long,int)        3.Thread的join,join(long),join(long,int)        4.InterruptibleChannel的io操作(这个很陌生!!!)        5.Selector的wakeup方法(这个很陌生!!!)        6.其他方法    如果另外一个线程调用阻塞线程的interrupt方法,则会打断这种阻塞,因此这种方法有时    会被称为可中断方法。打断一个线程并不等于该线程的生命周期的结束,仅仅是打断了当前    线程的阻塞状态。一旦线程在阻塞情况下被打断了,都会抛出一个称为InterruptedException    的异常,这个异常就像一个signal一样,高诉这个刚刚被中断的线程,哦,我刚刚是因为    中断被唤醒的啊~~~    要点:        interrupt()方法到底做了什么?在一个线程内部存在一个名为interrupt flag的标识        如果一个线程被interrupt,那么它的flag将会被设置。如果当前线程只在执行可中断的        方法,且被阻塞时,调用interrupt方法将其中断,反而会导致flag被清除~~~(什么乱        七八糟啊啊啊啊) */class ThreadInterrupt{    public static void test(){        Thread t = new Thread(()->{            try{                TimeUnit.MINUTES.sleep(1);            } catch (InterruptedException e) {                System.out.println("Oh,i am be interrupted...");            }        });        t.start();        try {            TimeUnit.MILLISECONDS.sleep(2);            t.interrupt(); //去叫醒这个兄弟!!!        } catch (InterruptedException e) {            e.printStackTrace();        }    }}/*    3.7.2 isInterrupted    isInterrupted是Thread的一个成员方法,它主要判断当前线程是否被中断,该方法仅仅是对    interrupt标识的一个判断,并不会影响标识发生任何改变。        ——我感觉作者没有把阻塞和中断的许多细节给讲清楚 */class ThreadIsInterrupted{    public static void test(){        Thread t = new Thread(){            @Override            public void run() {                while(true){                    //这个地方真的能被中断么???                    //do nothing                }            }        };        t.start();        try {            TimeUnit.MILLISECONDS.sleep(2);            System.out.printf("Thread is interrupted? %s",t.isInterrupted());            t.interrupt();            System.out.printf("Thread is interrupted? %s",t.isInterrupted());        } catch (InterruptedException e) {            e.printStackTrace();        }    }}class ThreadIsInterrupted2{    public static void test(){        Thread t = new Thread(){            @Override            public void run() {                while(true){                    try{                        TimeUnit.MINUTES.sleep(1);                    } catch (InterruptedException e) {                        System.out.printf("I am be interrupted? %s\n",isInterrupted());                    }                }            }        };        t.start();        try {            TimeUnit.MILLISECONDS.sleep(2);            System.out.printf("Thread is interrupted? %s \n",t.isInterrupted());            t.interrupt();            System.out.printf("Thread is interrupted? %s \n",t.isInterrupted());        } catch (InterruptedException e) {            e.printStackTrace();        }    }}/*===========================================================================                            实验总结===========================================================================实验结果分析:    1.调用interrupt这个方法了,这个方法只是简简单单的设置了一个flag    2.调用了isInterrupted这个方法了,也只是简简单单的去访问一下这个flag    3.线程中如果没有正在阻塞的方法, 你调用了interrupt是没有任何意义的,你设置的        这个flag根本没有方法去访问    4.如果线程正在某个方法上阻塞这,那么这个线程被分到时间片时,肯定先检查一下        这个flag的值,如果这个flag的值代表中断发生了,就让这个阻塞的方法返回        ,同时将这个flag复原。=========================================================================== *//*    3.7.3 interrupted    interrupted是一个静态方法,调用这个方法会擦除线程的interrupt表示,需要注意    的是,如果线程被打断了,那么第一次调用interrupted方法会返回true,并且立即擦    除interrupt标识~~~        ——我想知道的是,这个东西有什么用!!! */class ThreadInterrupted{    public static void test() {        Thread t = new Thread(){            @Override            public void run() {                while (true) {                    /*                        我有点不懂这个地方???,你调用的是一个                        静态方法,来消除的是一个对象的标识。。。                     */                    System.out.println(Thread.interrupted());                }            }        };        t.setDaemon(true);        t.start();        try {            TimeUnit.MILLISECONDS.sleep(2);            t.interrupted();        } catch (InterruptedException e) {            e.printStackTrace();        }    }}/*    3.7.4 interrupt注意事项        如果一个线程设置了interrupt标识,那么接下来的可中断方法会立即中断~~~            ——不然会造成中断信号丢失,问题更大 */class ThreadTest{    public static void test() {        System.out.println("Main thread is interrupted:"+Thread.interrupted());        Thread.currentThread().interrupt();        System.out.println("Main thread is interrupted now?"+Thread.currentThread().isInterrupted());        try{            TimeUnit.MINUTES.sleep(1);        } catch (InterruptedException e) {            System.out.println("I will be interrupted still.");        }    }}/*    3.8 线程join        public final void join() throws InterruptException        public final synchronized void join(long millis, int nanos) throws InterruptException        public final synchronized void join(long millis) throws InterruptException    3.8.1 线程join方法详解    有两种调用join的方法,main线程创建了A线程对象,然后调用A的join方法,这时候main线程会    等待A线程完成,然后在执行。还有一种就是在A线程内部的run方法中,调用了自生的join方法,不    知道在这种情况下会发生什么事情。 */class ThreadJoin{    public static void test() {        List
threads = IntStream.range(1,3) .mapToObj(ThreadJoin::create) .collect(toList()); threads.forEach(Thread::start); for (Thread thread : threads) { try { thread.join(); } catch (InterruptedException e) { e.printStackTrace(); } } for (int i = 0; i < 10; i++) { System.out.println(Thread.currentThread().getName()+"#"+i); shortSleep(); } } private static Thread create(int seq) { return new Thread(()->{ for (int i = 0; i < 10; i++) { System.out.println(Thread.currentThread().getName()+"#"+i); } },String.valueOf(seq)); } private static void shortSleep() { try{ TimeUnit.SECONDS.sleep(1); } catch (InterruptedException e) { e.printStackTrace(); } }}/* 3.8.2 join方法结合实战 需求: 如果你有一个APP,主要用于查询航班信息,你的APP是没有这些实时数据的,当用户发起查询 请求时,你需要到各大航空公司的接口获取信息,最后同意整理加工返回到APP客户端。当然 JDK自带了很多高级工具,比如CountDownLatch和CyclieBarrier等都可以完成类似的功能, 该例子是典型的串行任务局部并行化处理~~~用户在APP客户端输入出发地北京和目的地上海后, 服务端接受到这个请求之后,先来验证用户的信息,然后到各大航空公司的接口查询信息,最后 经过整理加工返回给客户端,每一个航空公司的接口不会都一样,获取数据格式也不一样,查询 的速度也存在差异,如果再更航空公司进行串行化交互(逐个地查询),很明显客户端需要等待 很长的时间,这样的话,用户体验就会非常差。如果我们将每个航空公司的查询都交给一个线程 去工作,然后在它们结束之后同意对数据进行整理,这样就可以极大的节约时间,从而提高用户 体验效果。 */interface FightQuery{ List
get();}class FightQueryTask extends Thread implements FightQuery{ private final String origin; private final String destination; private final List
fightList = new ArrayList<>(); public FightQueryTask(String airline,String origin,String destination){ super("["+airline+"]"); this.origin=origin; this.destination=destination; } @Override public void run() { System.out.printf("%s-query from %s to %s \n",getName(),origin,destination); int randomVal = ThreadLocalRandom.current().nextInt(10); try{ TimeUnit.SECONDS.sleep(randomVal); this.fightList.add(getName()+"-"+randomVal); System.out.printf("The Fight:%s list query successful\n",getName()); } catch (InterruptedException e) { e.printStackTrace(); } } @Override public List
get() { return this.fightList; }}class FightQueryExample{ private static List
fightCompany = Arrays.asList( "CSA","CEA","HNA" ); public static void test() { List
results = search("SH","BJ"); System.out.println("=================result================="); results.forEach(System.out::println); } private static List
search(String original,String dest){ final List
result = new ArrayList<>(); List
tasks = fightCompany.stream() .map(f->createSearchTask(f,original,dest)) .collect(toList()); tasks.forEach(Thread::start); tasks.forEach(t->{ try{ t.join(); } catch (InterruptedException e) { e.printStackTrace(); } }); tasks.stream().map(FightQueryTask::get) .forEach(result::addAll); return result; } private static FightQueryTask createSearchTask( String fight, String original, String dest ){ return new FightQueryTask(fight,original,dest); }}/* ************************************************************************* ************************************************************************* ************************************************************************* ************************************************************************* *//* 3.9 如何关闭一个线程 3.9.1 正常关闭 1.线程结束,生命周期正常结束 2.捕获中断信号关闭线程 用过new Thread的方法创建线程,因此在用这种方式创建的一个线程中往往会循环地执行 某个任务,比如心跳检查,不断地接受网络消息报文等,系统决定退出的时候,可以借助中断 线程的方式使其退出。 ——因为用new Thread创建线程成本高,所以我们不能把它当快餐线程,所以我们 得让它疯狂的循环处理事务,又因为它在疯狂的循环,所以我们得用中断的方式 让它退出来。。。阿门 */class InterrupThreadExit{ public static void test() { /* 没有调用可中断方法的,可以利用检测标志位。。。 */ Thread t = new Thread(){ public void run(){ System.out.println("I will start work"); while(!isInterrupted()){ //working } System.out.println("I will be exiting..."); } }; /* 调用了可中断方法的,可以通过捕获中断异常。。。 */ Thread t2 = new Thread(){ public void run(){ System.out.println("I will start work"); while(true){ try{ TimeUnit.MILLISECONDS.sleep(1); } catch (InterruptedException e) { break; } } System.out.println("I will be exiting..."); } }; t.start(); try { TimeUnit.MINUTES.sleep(1); System.out.println("System will be shutdown."); t.interrupt(); } catch (InterruptedException e) { e.printStackTrace(); } }}/* 3.使用volatile开关控制 由于interrupt标识很有可能白擦除,或者逻辑单元中不会调用任何可中断方法,所以使用 volatile修饰的开关flag关闭线程也是一种常用的做法: */class FlagThreadExit{ static class MyTask extends Thread{ private volatile boolean close = false; @Override public void run() { System.out.println("I will start work"); while(close&&!isInterrupted()){ //working } System.out.println("I will be exiting."); } public void close(){ this.close=true; this.interrupt(); } } public static void test() { MyTask t = new MyTask(); t.start(); try { TimeUnit.MINUTES.sleep(1); System.out.println("sys will be shutdown."); t.close(); } catch (InterruptedException e) { e.printStackTrace(); } }}/* 3.9.2 异常退出 在一个线程的执行单元中,是不允许抛出checked异常的。如果线程在运行过程中需要捕获 checked异常并且判断是否还有运行下去的必要,那么此时可以将checked异常封装封装 成unchecked异常抛出,进而结束线程的生命周期。 3.9.3 进程假死 进程出现假死,可能是某个线程阻塞了,或者线程出现了死锁的情况。可以利用jstack、 jconsole、jvisualvm等工具进行诊断。 */

 

——《Java高并发编程详解》

转载于:https://www.cnblogs.com/junjie2019/p/10585451.html

你可能感兴趣的文章
数据结构之排序三:插入排序
查看>>
Class.forName(),classloader.loadclass用法详解
查看>>
vue route 跳转
查看>>
Device Tree Usage
查看>>
【雷电】源代码分析(二)-- 进入游戏攻击
查看>>
POJ 1220 高精度/进制转换
查看>>
cocos2d-x中CCLabelAtlas的小图片拼接
查看>>
【学习笔记】深入理解js原型和闭包系列学习笔记——精华
查看>>
深入理解js——prototype原型
查看>>
Entityframework:“System.Data.Entity.Internal.AppConfig”的类型初始值设定项引发异常。...
查看>>
Ubuntu 安装之python开发
查看>>
恶心的struts标签,等我毕业设计弄完了,瞧我怎么收拾你。
查看>>
Linux中防火墙centos
查看>>
hudson+apachecontinuum+ant
查看>>
mysql新建用户,用户授权,删除用户,修改密码
查看>>
实验五 TCP传输及加密
查看>>
【iOS】build diff: /../Podfile.lock: No such file or directory
查看>>
【Android Studio】使用 Genymotion 调试出现错误 INSTALL_FAILED_CPU_ABI_INCOMPATI
查看>>
FancyCoverFlow
查看>>
教你一分钟实现动态模糊效果
查看>>