Java线程基础知识(状态、共享与协作)
1.基础概念
CPU核心数和线程数的关系
核心数:线程数=1:1 ;使用了超线程技术后---> 1:2CPU时间片轮转机制
又称RR调度,会导致上下文切换什么是进程和线程
进程:程序运行资源分配的最小单位,进程内部有多个线程,会共享这个进程的资源
线程:CPU调度的最小单位,必须依赖进程而存在。澄清并行和并发
并行:同一时刻,可以同时处理事情的能力
并发:与单位时间相关,在单位时间内可以处理事情的能力高并发编程的意义、好处和注意事项
好处:充分利用cpu的资源、加快用户响应的时间,程序模块化,异步化
问题:
线程共享资源,存在冲突;
容易导致死锁;
启用太多的线程,就有搞垮机器的可能查看 JVM自启动线程
Attach Listener :线程是负责接收到外部的命令,而对该命令进行执行的并且吧结果返回给发送者。通常我们会用一些命令去要求jvm给我们一些反馈信息,如:java -version、jmap、jstack等等。如果该线程在jvm启动的时候没有初始化,那么,则会在用户第一次执行jvm命令时,得到启动。
signal dispather: 前面我们提到第一个Attach Listener线程的职责是接收外部jvm命令,当命令接收成功后,会交给signal dispather线程去进行分发到各个不同的模块处理命令,并且返回处理结果。signal dispather线程也是在第一次接收外部jvm命令时,进行初始化工作。
Finalizer: 用来执行所有用户Finalizer 方法的线程
Reference Handler :它主要用于处理引用对象本身(软引用、弱引用、虚引用)的垃圾回收问题。
public static void main(String[] args) {
ThreadMXBean threadMXBean = ManagementFactory.getThreadMXBean();
ThreadInfo[] threadInfos = threadMXBean.dumpAllThreads(false, false);
for (ThreadInfo threadInfo : threadInfos) {
System.out.println("[" + threadInfo.getThreadId() + "]" + " " + threadInfo.getThreadName());
}
}
- Java management包
management包中提供了比较全面的监控和管理工具,包括JVM的监管API、监管API日志等等。 - 管理接口
PlatformManagementObject接口:所有的管理接口都要继承该接口,这个接口是从1.7才出现的,从其文档的注释中可以看到其存在的价值是为以后平台的扩展而设计的,而不是为了应用程序。
BufferPoolMXBean接口:缓冲池管理接口包括direct和mapped类型的缓冲池。
ClassLoadingMXBean接口:类加载管理接口,可以监控管理虚拟机类加载系统。
CompilationMXBean接口:虚拟机的编译系统的管理与监控。
GarbageCollectorMXBean接口:虚拟机垃圾收集的管理接口,通过该接口可以查看垃圾收集的时间和次数。
MemoryManagerMXBean接口:该接口用于内存管理,其中,垃圾收集器属于该类型的内存管理器。
MemoryMXBean接口:用于虚拟机的内存管理,执行GC、获取堆内存和非堆内存相关数据。
MemoryPoolMXBean接口:用于内存池的管理,所谓的内存池表示的是虚拟机使用和内存管理者管理的内存资源。
OperatingSystemMXBean接口:操作系统管理接口,可以查看系统的平均负载、系统参数、可用的进程数、系统版本和名称等等。
PlatformLoggingMXBean接口:日志管理接口,可以设置日志级别、获取日志名称等等。
RuntimeMXBean接口:虚拟机运行时管理接口,获取虚拟机的名称、虚拟机版本、获取java的classpath、获取系统参数等。
ThreadMXBean接口:虚拟机线程管理。可以获取线程数、获取线程Id、线程信息、当前线程CPU时间、当前线程用户时间、查看死锁线程等等。 - 信息类实体
LockInfo:任何的java锁(简单的java锁和Concurrent包中所使用的锁,AbstractOwnableSynchronizer和Condition的实现类/子类)。
MemoryUsage:内存使用快照,用于获取每个虚拟机或者堆或者虚拟机非堆内存池作为整体的使用信息。
MemoryNotificationInfo:内存通知的信息。
MonitorInfo:继承自LockInfo,同步代码块或者是同步方法上的锁。
ThreadInfo:线程信息,包括线程名称,线程id,阻塞时间,阻塞次数,等待时间,等待次数,锁信息,锁名称,锁拥有者id等。
ManagementPermission:权限管理类。 - 工厂类
ManagementFactory:MXBean通过该工厂类进行获取,使用了工厂模式管理,经过该类获取到相应的MXBean类之后再调用其中的方法得到需要管理和监控的信息。
2.Java的三种线程创建方式
类Thread
接口Runnable
接口Callable
接口Runnable与接口Callable区别
(1)Callable规定的方法是call(),Runnable规定的方法是run()。其中Runnable可以提交给Thread来包装下,直接启动一个线程来执行,而Callable则一般都是提交给ExecuteService来执行。
(2)Callable的任务执行后可返回值,而Runnable的任务是不能返回值得
(3)Callable方法可以抛出异常,Runnable方法不可以
(4)运行Callable任务可以拿到一个Future对象,表示异步计算的结果。
3.Java线程的状态
进入Blocked状态,是在竞争锁的过程中,比如synchronized导致的竞争。从而进入blocked状态。
Waiting/Timed_Waiting是在调用了wait()之后,进入了waiting状态。待notify()/notifyAll()之后,就进入Blocked状态。然后竞争锁,从而可以获取处理机,进行执行操作。Notify() vs NotifyAll()
notify: 从waiting等待队列中,随机选取一个线程进行唤醒。
notifyAll: 将改对象的waiting等待队列中的所有线程唤醒,并入blocked状态。然后由其自由竞争锁,依次执行,最终直到所有的线程都依次获取锁,并执行完毕。队列中就没有等待的线程。线程只有6种状态。整个生命周期就是这几种状态的切换。
run()和start() :run方法就是普通对象的普通方法,只有调用了start()后,Java才会将线程对象和操作系统中实际的线程进行映射,再来执行run方法。
run 和 start区别代码StartAndRun.javayield() :让出cpu的执行权,将线程从运行转到可运行状态,但是下个时间片,该线程依然有可能被再次选中运行。
线程的优先级
取值为1~10,缺省为5,但线程的优先级不可靠,不建议作为线程开发时候的手段守护线程
和主线程共死,finally不能保证一定执行
DaemonThread.java线程自然终止:自然执行完或抛出未处理异常
stop(),resume(),suspend()已不建议使用,stop()会导致线程不会正确释放资源,suspend()容易导致死锁。问题:interrupt是怎样避免suspend之类的死锁的?是使用wait notify实现的?
java线程是协作式,而非抢占式
调用一个线程的interrupt() 方法中断一个线程,并不是强行关闭这个线程,只是跟这个线程打个招呼,将线程的中断标志位置为true,线程是否中断,由线程本身决定。
isInterrupted() 判定当前线程是否处于中断状态。
static方法interrupted() 判定当前线程是否处于中断状态,同时中断标志位改为false。
方法里如果抛出InterruptedException,线程的中断标志位会被复位成false,如果确实是需要中断线程,要求我们自己在catch语句块里再次调用interrupt()。
抛出异常HasInterruptException.java
参考EndRunnable.java
参考EndThread.java
-----------------------------------补充---------------------------------------当一个方法后面声明可能会抛出InterruptedException 异常时,说明该方法是可能会花一点时间,但是可以取消的方法。
抛InterruptedException的代表方法有:
- java.lang.Object 类的 wait 方法
- java.lang.Thread 类的 sleep 方法
- java.lang.Thread 类的 join 方法
执行wait方法的线程,会进入等待区等待被notify/notify All。在等待期间,线程不会活动。
执行sleep方法的线程,会暂停执行参数内所设置的时间。
执行join方法的线程,会等待到指定的线程结束为止。
因此,上面的方法都是需要花点时间的方法。
- sleep方法与interrupt方法
interrupt方法是Thread类的实例方法,在执行的时候并不需要获取Thread实例的锁定,任何线程在任何时刻,都可以通过线程实例来调用其他线程的interrupt方法。
当在sleep中的线程被调用interrupt方法时,就会放弃暂停的状态,并抛出InterruptedException异常,这样一来,线程的控制权就交给了捕捉这个异常的catch块了。 - wait方法和interrupt方法
当线程调用wait方法后,线程在进入等待区时,会把锁定接触。当对wait中的线程调用interrupt方法时,会先重新获取锁定,再抛出InterruptedException异常,获取锁定之前,无法抛出InterruptedException异常。 - join方法和interrupt方法
当线程以join方法等待其他线程结束时,一样可以使用interrupt方法取消。因为join方法不需要获取锁定,故而与sleep一样,会马上跳到catch程序块
4.线程的共享
- synchronized内置锁
对象锁,锁的是类的对象实例。
类锁 ,锁的是每个类的的Class对象,每个类的的Class对象在一个虚拟机中只有一个,所以类锁也只有一个。
对象锁和类锁SynClzAndInst.java - volatile关键字
适合于只有一个线程写,多个线程读的场景,因为它只能确保可见性。
volatile不能保证线程安全VolatileUnsafe.java - ThreadLocal
线程局部变量。可以理解为是个map,类型 Map<Thread,Integer>
ThreadLocal保证互不干扰UseThreadLocal.java
5.线程的协作
等待和通知的标准范式
等待方:
1.获取对象的锁
2.循环里判断条件是否满足,不满足调用wait方法
3.条件满足执行业务逻辑
通知方:
1.获取对象锁
2.改变条件
3.通知所有等待在对象的线程notify和notifyAll应该用谁?
尽量使用notifyAll,使用notify有可能发生信号丢失的情况。
notify和notifyAll实例-快递类Express.java
notify和notifyAll实例-测试类TestWN.java等待超时模式实现一个连接池
假设等待时长T,当前时间now + T以后超时
等待超时模式——数据库连接池框架
核心类wait-notifyAll DBPool.java
测试类DBPoolTest.java
long overtime = now + T
long remain = T;
while (result 不满足条件 && remain > 0) {
wait(remain);
remain = overtime – now;
}
return result;
- join()方法
保证线程A在线程B执行后再继续执行:join和CountDownLatch
join嵌套插队 UseJoin.java - 调用yield() 、sleep()、wait()、notify()等方法对锁有何影响?
yield后,所持有的锁是不释放的
sleep,持有的锁是不释放
在调用wait()前,必须持有锁,调用wait之后,锁自动释放,当wait返回时,线程会重新持有锁
notifyAll调用前持有锁,调用notifyall本身不会释放锁,所以一般放到方法最后
sleep持有锁时不会释放 SleepLock.java
转自:https://www.jianshu.com/p/492f45ea7e64
Java线程基础知识(状态、共享与协作)的更多相关文章
- java线程基础知识----线程基础知识
不知道从什么时候开始,学习知识变成了一个短期记忆的过程,总是容易忘记自己当初学懂的知识(fuck!),不知道是自己没有经常使用还是当初理解的不够深入.今天准备再对java的线程进行一下系统的学习,希望 ...
- Java 线程基础知识
前言 什么是线程?线程,有时被称为轻量进程(Lightweight Process,LWP),是程序执行流的最小单元.一个标准的线程由线程 ID,当前指令指针 (PC),寄存器集合和堆栈组成.另外,线 ...
- java线程基础知识----线程与锁
我们上一章已经谈到java线程的基础知识,我们学习了Thread的基础知识,今天我们开始学习java线程和锁. 1. 首先我们应该了解一下Object类的一些性质以其方法,首先我们知道Object类的 ...
- java线程基础知识----java daemon线程
java线程是一个运用很广泛的重点知识,我们很有必要了解java的daemon线程. 1.首先我们必须清楚的认识到java的线程分为两类: 用户线程和daemon线程 A. 用户线程: 用户线程可以简 ...
- java线程基础知识----java线程模型
转载自http://www.cnblogs.com/nexiyi/p/java_memory_model_and_thread.html 1. 概述 多任务和高并发是衡量一台计算机处理器的能力重要指标 ...
- java线程基础知识----SecurityManager类详解
在查看java Thread源码的时候发现一个类----securityManager,虽然很早就知道存在这样一个类但是都没有深究,今天查看了它的api和源码,发现这个类功能强大,可以做很多权限控制策 ...
- Java 多线程——基础知识
java 多线程 目录: Java 多线程——基础知识 Java 多线程 —— synchronized关键字 java 多线程——一个定时调度的例子 java 多线程——quartz 定时调度的例子 ...
- JAVA相关基础知识
JAVA相关基础知识 1.面向对象的特征有哪些方面 1.抽象: 抽象就是忽略一个主题中与当前目标无关的那些方面,以便更充分地注意与当前目标有关的方面.抽象并不打算了解全部问题,而只是选择其中的一部分, ...
- 什么才是java的基础知识?
近日里,很多人邀请我回答各种j2ee开发的初级问题,我无一都强调java初学者要先扎实自己的基础知识,那什么才是java的基础知识?又怎么样才算掌握了java的基础知识呢?这个问题还真值得仔细思考. ...
随机推荐
- 【CF850E】Random Elections FWT
[CF850E]Random Elections 题意:有n位选民和3位预选者A,B,C,每个选民的投票方案可能是ABC,ACB,BAC...,即一个A,B,C的排列.现在进行三次比较,A-B,B-C ...
- 在eclipse中编辑linux上的项目
以前在linux的上接口自动化项目都是使用notepad++或SVN下载到本地后再上传来完成功做,但在调试时非常麻烦. 查看了下在eclipse中有一个非常好用的插件Remote Systems,可以 ...
- 关于IP地址子网的划分
- 基于pandas python的美团某商家的评论销售数据分析(可视化)
基于pandas python的美团某商家的评论销售数据分析 第一篇 数据初步的统计 本文是该可视化系列的第二篇 第三篇 数据中的评论数据用于自然语言处理 导入相关库 from pyecharts i ...
- 利用javascript判断文件是否存在
1 判断本地文件是否存在 var fso,s=filespec; // filespec="C:/path/myfile.txt" fso=new ActiveXObject(&q ...
- 堆内存泄漏移除导致tcp链接异常高
故障现象: 1:活动前端Nginx服务器TCP连接数到1万多 2:活动后端Tomcat其中1台TCP连接数达4千,并且CPU瞬间到780%(配置8核16G),内存正常 3:重启后端Tomcat后,TC ...
- 关于ArcGIS Server修改数据源是否对切片服务有影响
感谢一路走来默默支持和陪伴的你~~~ ------------------欢迎来访,拒绝转载------------------- (一)问题: 一直有人问一个问题: 1.我发布了切片的地图服务一以后 ...
- 英特尔和 Google 的 OKR 制度与我们一般所说的 KPI 有什么不同?
英特尔和 Google 的 OKR 制度与我们一般所说的 KPI 有什么不同? - 知乎 https://www.zhihu.com/question/22478049?sort=created 知乎 ...
- LDAP summary-- Python ldap
A DN is comprised of a series of RDNs (Relative Distinguished Names) found by walking UP the tree (D ...
- ECharts修改坐标轴,坐标轴字体,坐标轴网格样式以及控制坐标轴是否显示
转自:http://blog.csdn.net/kirinlau/article/details/72876689 首先要将一个图表显示在前端页面上: var myChart = echarts.in ...