Thread API的详细介绍
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<Thread> 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<String> get(); } class FightQueryTask extends Thread implements FightQuery{ private final String origin; private final String destination; private final List<String> 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<String> get() { return this.fightList; } } class FightQueryExample{ private static List<String> fightCompany = Arrays.asList( "CSA","CEA","HNA" ); public static void test() { List<String> results = search("SH","BJ"); System.out.println("=================result================="); results.forEach(System.out::println); } private static List<String> search(String original,String dest){ final List<String> result = new ArrayList<>(); List<FightQueryTask> 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高并发编程详解》
Thread API的详细介绍的更多相关文章
- 微服务架构学习与思考(10):微服务网关和开源 API 网关01-以 Nginx 为基础的 API 网关详细介绍
微服务架构学习与思考(10):微服务网关和开源 API 网关01-以 Nginx 为基础的 API 网关详细介绍 一.为什么会有 API Gateway 网关 随着微服务架构的流行,很多公司把原有的单 ...
- 微服务架构学习与思考(11):开源 API 网关02-以 Java 为基础的 API 网关详细介绍
微服务架构学习与思考(11):开源 API 网关02-以 Java 为基础的 API 网关详细介绍 上一篇关于网关的文章: 微服务架构学习与思考(10):微服务网关和开源 API 网关01-以 Ngi ...
- 【并发编程】关于Thread类的详细介绍
多线程编程基础--Thread类 Thread类是Java中实现多线程编程的基础类.本篇博客就来介绍下Thread类的常用API和常见用法. Thread类常用的方法如下: Thread.active ...
- Xcode中c++&Object-C混编,详细介绍如何在cocos2dx中访问object函数以及Apple Api
转自:http://www.himigame.com/iphone-cocos2dx/743.html Cocos2dx系列博文的上一篇详细介绍了如何在Xcode中利用jni调用Android的Jav ...
- Java 并发专题 : Executor详细介绍 打造基于Executor的Web服务器
转载标明出处:http://blog.csdn.net/lmj623565791/article/details/26938985 继续并发,貌似并发的文章很少有人看啊~哈~ 今天准备详细介绍java ...
- 城市经纬度 json 理解SignalR Main(string[] args)之args传递的几种方式 串口编程之端口 多线程详细介绍 递归一个List<T>,可自己根据需要改造为通用型。 Sql 优化解决方案
城市经纬度 json https://www.cnblogs.com/innershare/p/10723968.html 理解SignalR ASP .NET SignalR 是一个ASP .NET ...
- kvm详细介绍
KVM详解,太详细太深入了,经典 2016-07-18 19:56:38 分类: 虚拟化 原文地址:KVM详解,太详细太深入了,经典 作者:zzjlzx KVM 介绍(1):简介及安装 http:// ...
- 详细介绍如何自研一款"博客搬家"功能
前言 现在的技术博客(社区)越来越多,比如:imooc.spring4All.csdn.cnblogs或者iteye等,有很多朋友可能在这些网站上都发表过博文,当有一天我们想自己搞一个博客网站时就会发 ...
- Java 集合系列05之 LinkedList详细介绍(源码解析)和使用示例
概要 前面,我们已经学习了ArrayList,并了解了fail-fast机制.这一章我们接着学习List的实现类——LinkedList.和学习ArrayList一样,接下来呢,我们先对Linked ...
随机推荐
- GIS基础软件及操作(十)
原文 GIS基础软件及操作(十) 练习十.网络分析 (1) 加深对网络分析基本原理.方法的认识:(2) 熟练掌握ARCGIS下进行道路网络分析的技术方法:(3) 结合实际.掌握利用网络分析方法解决地学 ...
- JavaScript API for Office Outlook Add-in - “一页纸文档“
上一篇文章 Office Add-in Model 为 Outlook Mail Add-in 提供的 JavaScript API 介绍 ,简单地在表格中列出了所有的 Object 定义,但是个人感 ...
- 解决C/C++程序执行一闪而过的方法(使用getchar,或者cin.get,不推荐system(“pause”))
简述 在VS编写控制台程序的时候,包括使用其他IDE(Visual C++)编写C/C++程序,经常会看到程序的执行结果一闪而过,要解决这个问题,可以在代码的最后加上system(“pause”).g ...
- vista下开机启动 简单绕过UAC的方法(自己使用runas参数重新启动自己,有点意思)
背景 vista下,如果不开启UAC,那就没有我下面要说的问题了,呵呵.下面说的都是在vista开启UAC的前提下说的,win7也适用. 在vista下,系统开启了UAC,如果你的 ...
- Python正则表达式进阶-零宽断言
1. 什么是零宽断言 有时候在使用正则表达式做匹配的时候,我们希望匹配一个字符串,这个字符串的前面或后面需要是特定的内容,但我们又不想要前面或后面的这个特定的内容,这时候就需要零宽断言的帮助了.所谓零 ...
- URL重写 httpModules IIS7
<system.web> <httpModules> <!--URL重写:IIS 及以下用次处配置--> <!--add name="MyHttpM ...
- Linux基础(二)
网卡的启动与关闭 ipup ens33 启动网卡 ifdown 关闭网卡 普通用户没有该权限 root用户,管理员,普通用户的权限 root 至高无上的 root用户所在的组是root组 管理员 ...
- kafka笔记6
我们讨论可靠性时,一般使用保证这个词,它是确保系统在各种不同的环境下能够发生一致的行为.Kafka可以在哪些方面作出保证呢? 1.Kafka可以保证分区消息的顺序 2.只有消息被写入分区的所有同步副本 ...
- spring boot单元测试之RestTemplate(三)——api详解
本篇内容来自翟永超的<Springcloud微服务实战>,转载请注明. 一.GET请求 在RestTemplate中,对GET请求可以通过如下两个方法进行调用实现. 第一种:getForE ...
- python连接数据库(1)——mysql
mysql是世界上应用最广的免费数据库,python当然也提供了对它的调用. 首先pip install pymysql,当然自己要知道数据库的用户名和密码,本地数据库的host就是localhost ...