多线程
概念
线程分为执行时间与等待事件,在一个线程的等待事件中可以执行其他线程
线程继承于线程类Thread并重写run方法,当线程启动时自动执行run方法
多线程的运行顺序时随机的
线程分为用户线程与守护线程,守护线程为其他线程提供服务,如垃圾回收器(GC),且不能单独运行,当JVM中没有其他用户线程只有守护线程时,守护线程自动销毁,JVM会退出。
创建线程
声明类继承Thread类并创建一个该类对象
1
MyThread thread=new MyThread();
声明类实现Runnable接口并创建一个该类对象,声明一个Thread类对象(传入Runnable对象)
1
2MyRunnable runnable=new MyRunnable();
Thread thread=new Thread(runnable);声明类实现Callable接口并创建一个该类对象,创建一个FutureTask对象并调用
1
2
3Callable<Integer> callable = new MyCallable();
FutureTask<Integer> futureTask = new FutureTask<>(callable);
Thread thread = new Thread(futureTask);
线程的一些常用方法
1 | currentThread() 当前运行的线程 |
附:
- 当前线程表示运行该代码时运行的代码所在线程,如在main线程中使用MyThread类构造方法时处于main线程中
- 某线程结束运行后其ID可能被后续线程使用
- 优先级越高的线程获得的CPU资源越多,不能保证优先级越高的线程先运行,优先级设置不当可能会导致某些线程永远无法得到运行,即线程饥饿,一般编写代码不进行线程优先级设置
- 线程标志中断后该线程需要自己检测是否中断并执行
- 设置守护线程应该在线程运行之前就设置完毕
线程生命周期
线程生命周期可以通过getState()
方法获得,线程状态有:
- NEW,新建状态,即
start()
启动之前 - RUNNABLE,可运行状态,是一个复合状态,包括READY和RUNNING,READY状态可以被线程调度器调度使之处于RUNNING状态,RUNNING状态可通过
Thread.yield()
方法转换为READY状态 - BLOCKED,阻塞状态,线程发起阻塞的I/O操作,或申请由其他线程的独占资源,线程会转换为BLOCKED,不会占用CPU资源,当发起阻塞的I/O操作结束或获得申请的资源,线程可以转为RUNNABLE
- WAITING,等待状态,线程执行了
Object.wait(),Thread.join()
方法转换为WAITING状态,执行Object.notify()
方法,或加入线程完毕转换为RUNNABLE状态 - TIMED_WAITING,类似于WAITING,但线程如果没有在指定时间范围完成期望操作,该线程会自动转换为RUNNABLE
- TERMINATED,终止状态,线程结束
其他性质
线程原子性
线程对数据操作的不可分割性
使一个数同一时间只能被一个线程调用定义AtomicInteger
变量
线程可见性
一个线程对数据的更新结果可以被其他线程读取则称为可见
重排序
不同处理器上执行的的多个操作顺序可能不同,可能导致线程安全问题
注解
@
+注释名在代码中存在,如重写注解@Override
内置注解
注解名 | 含义 |
---|---|
@Override |
重写 |
@Deprecated |
已过时,不推荐使用的方法 |
@SuppressWarnings() |
镇压警告 |
元注解
负责注解其他注解的注解
注解名 | 含义 |
---|---|
@Target() | 描述注解使用范围 |
@Retention() | 在什么级别保存注释信息(SOURCE,CLASS,RUNTIME) |
@Documented | 说明注解将生成在javadoc中 |
@Inherited | 说明子类可以继承父类中的该注解 |
自定义注解
使用@interface
自定义注解
其中声明的参数在使用时必须添加,可以有默认值
1 | MyAnnotation{ |
反射
区分静态动态语言
Class类
常用方法
方法名 | 功能 |
---|---|
static Class.forName(String name) |
返回指定名的Class对象 |
Object newInstance() |
调用缺省构造函数,返回Class对象实例 |
getName() |
返回此Class对象表示的实体名 |
Class getSuperClass() |
返回当前Class对象的父类Class对象 |
Class[] getinterfaces() |
获取当前对象接口 |
ClassLoader getClassLoader() |
返回该类的类加载器 |
ClassLoader getConstructors() |
返回包含某些Constructors 对象的数组 |
Method getMethod(String name, Class...T) |
返回Method对象,此对象形参类型为paramType |
Field[] getDeclaredFields() |
返回Field对象的数组 |
有Class对象的类型
注意:一个类/类型只有一个Class对象
如:类型相同长度不同的两个数组是同一对象,两者getClass()的hashCode相同
主动/被动初始化
类加载器
双亲委派机制
如果一个类加载器收到了一个类加载请求,它不会自己去尝试加载这个类,而是把这个请求转交给父类加载器去完成。每一个层次的类加载器都是如此。因此所有的类加载请求都应该传递到最顶层的启动类加载器中,只有到父类加载器反馈自己无法完成这个加载请求(在它的搜索范围没有找到这个类)时,子类加载器才会尝试自己去加载。委派的好处就是避免有些类被重复加载。
![双亲委派机制](https://img-blog.csdnimg.cn/20201217213314510.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L2NvZGV5YW5iYW8=,size_16,color_FFFFFF,t_70)
获取类运行时的结构
1 | Class c1 = Class.forName("")//获取Class对象 |
得到Class对象之后
通过构造器实例化对象
1 | Constructor constructor; |
注:constructor.newInstance()
实例化新对象
通过反射调用普通方法
1 | User user1 = new User(); |
通过反射更改私有属性
1 | User user1 = new User(); |