1.进程和线程的区别
进程是资源分配的最小单位,线程是cpu调度的最小单位。
*所有与进程相关的资源,都被记录在PCB中
*进程是抢占cpu的调度单位;线程属于某个进程,共享其资源
*线程只由堆栈寄存器、程序计数器和TCB组成
*进程有独立的地址空间,相互不影响,线程只是执行进程的不同执行路径
Java进程和线程的关系
*Java对操作系统提供的功能进行包装,包括线程和进程。
*运行一个程序会产生一个进程,一个进程至少会包含一个线程。
*每个进程对应一个JVM实例,多个线程共享JVM里的堆。
*java采用单线程编程模式,程序会自动创建主线程。
如何处理线程的返回值
1.主线程等待法
2.使用Thread类的join()方法,阻塞当前线程以等待子线程的处理完毕
3.通过Callable接口实现:通过FutureTask 或者 线程池获取
线程的状态
1.新建(new):创建线程后还没有启动,即还没有调用start()方法
2.运行(Runnable):包含running(正在执行)和ready(等待cpu的调度)
3.无限期的等待(waiting):不会被分配cpu执行时间,需要被显示唤醒
4.限期等待(timed Waiting):在一定时间后会被自动唤醒
5.阻塞(Blocking):等待获取排它锁
6.结束(terminated):已经终止的线程状态
sleep和wait的差别
基本差别:
1.sleep是Thread的方法,wait是Object的方法是一个本地方法
2.sleep可以在任何地方使用,wait只能在synchornized方法和synchronized块中使用
本质区别:
1.sleep只会让出cpu,不会导致锁行为的改变
2.wait不仅会让出cpu还会释放已经占有的同步资源锁
notify和notifyall的区别
锁池 :假设线程A拥有了一个对象的(不是类锁)锁,而其他线程B、C想调用这个对象的synchornized方法或同步块,由于该对象的锁正被A线程所占用,此时B、C线程便会被阻塞,进入一个地方去等待锁的释放,这个地方就是该对象的锁池。
等待池:假设线程A调用了某个对象的wait()方法,线程A就会释放该对象的锁,同时线程A就会进入到该对象的等待池中,进入到等待池的锁不会去竞争该对象的锁。
notifyall:会让所有处于等待池的全部线程全部进入到锁池去竞争获取锁的机会。
notify:只会随机选取一个处于等待池的线程进入锁池去竞争获取锁的机会。
yield:当调用Thread.yield(),会给线程调度器一个当前线程愿意让出cpu的暗示,但线程调度器可能忽视这个暗示。
interrupt():调用这个方法,通知线程应该中断了:1.如果线程处于被阻塞状态,则线程会立即抛出被阻塞状态,并抛出一个异常
2.如果线程处于正常活动状态,那么该线程的中断标志设为true。被中断标志的线程将继续正常工作,不受影响。
目前使用的方法:需要被调用的线程配合中断。
synchronized的底层实现:
Monitor:每个java对象天生自带了一把看不见的锁。
Java内存模型:
java内存模型本身是一种抽象的概念,并不真实存在,它描述的是一种规范,通过这种规范定义程序中各个变量的访问方式。
JMM中的主内存:1.存储了Java的实例对象
2.包括成员变量、类信息、常量、静态变量等。
3.属于公共区域,多线程并发操作时会引起线程安全问题。
JMM中的工作内存:1.存储了当前方法的所有本地信息的拷贝,本地变量对其他线程不可见。
2.字节码行号指示器,Native本地方法。
3.属于线程私有区域,不存在线程安全问题。
JMM和Java内存区域的划分属于不同的概念层次:
1.相似点:都存在共享区域和似有区域,在某个程度上讲公共区域代表了堆和方法区,私有区域代表了程序计数器,虚拟机栈以及本地方法栈。
主内存和工作内存的数据存储类型以及操作方式的归纳:
1.方法的基本类型本地变量将直接存储在工作内存的栈帧中。
2.引用类型的本地变量:引用存储在工作内存中,对象存储在主内存中。
3.成员变量、static变量、类信息将会存储在主内存中。
4.主内存共享的方式是线程各拷贝一份数据到工作内存中,操作完成之后刷新到主内存。
volatile是JVM提供的轻量级同步机制:保证volatile修饰的共享变量对所有线程总是可见的。
当对被volatile修饰的变量进行非原子操作时可能引发线程安全问题。比如:
此时可以在方法上加入synchronized关键字以保证线程的安全,因为synchronized的会创建一个内存屏障,这个指令以保证所有的cpu结果都会刷到主存中。
什么时候可以使用volatile关键字呢?当对被volatile修饰的变量进行原子操作时。
J.U.C的三个Executor的接口
Executor:运行新任务的简单接口,将任务进行提交和任务提交进行细节解耦。
ExecutorService:具备管理执行器和任务生命周期的方法,提交任务机制更加完善。