进程
进程本质是一个正在执行的程序。程序运行时,系统会创建进程,并给进程分配独立的内存空间。
CPU时间片切换
CPU时间片切换时,进程需要从切换之前运行的位置开始执行,所以进程还包括程序计数器、堆栈指针。
单核CPU时,在任意时刻只会有一个进程被CPU调度。
操作系统利用CPU时间片切换,从宏观层面实现多应用并发。
线程
Java中本身不存在线程,线程是由操作系统提供的(Java -> JVM->OS操作系统)
线程的优势
1.在多核CPU中,多线程可以实现真正意义的并行。
2.一个应用进程中,不同任务由不同线程处理,避免任务顺序执行而引起的阻塞问题,提升程序的实时性。
3.线程可以认为是轻量级的进程,所以线程的创建、销毁比进程更快。
4.线程有独有的超线程技术,将一个物理CPU模拟成两个逻辑CPU,让单个物理CPU就能使用线程级的并行计算,但如果两个线程同时需要某个资源时,其中一个线程必须挂起,直到这些资源空闲以后才能继续。超线程技术能提升40%左右的性能。
5.线程的异步执行能更好的提升并发吞吐量。
线程的实现方式
继承Thread类
public class MyThread extends Thread {
public void run() {
System.out.println("MyThread.run()");
}
}
MyThread myThread1 = new MyThread();
MyThread myThread2 = new MyThread();
//启动一个新线程去执行run(), start()内部调用的是一个native方法(private native void start0();)
myThread1.start();
myThread2.start();
实现Runnable接口
public class MyThread implements Runnable {
public void run() {
System.out.println("MyThread.run()");
}
}
实现callable接口
public class TaskRunnableForDoc implements Callable<Boolean> {
@Override
public Boolean call(){
try {
//TODO
}catch (Exception e){
return false;
}
return true;
}
}
public ThreadPoolTaskExecutor taskExecutor;
public void workForDoc(){
try{
Future<Boolean> future = taskExecutor.submit(new TaskRunnableForDoc());
System.out.println(future.get()); //阻塞、获取返回值
}catch (Exception e){
e.printStackTrace();
}
}
线程的生命周期
NEW
初始状态,线程被构建,但还没有调用start()。
RUNNABLED
运行状态,就绪和运行统称运行中
BLOCKED
阻塞状态(锁阻塞状态),线程放弃了CPU使用权,阻塞分以下几种:
等待阻塞
运行的线程执行wait(),JVM会把当前线程放入等待队列。
同步阻塞
运行的线程获取对象的同步锁时,如果同步锁被其他线程锁占用,JVM会把当前线程放入锁池。
其他阻塞
运行的线程执行Thread.sleep()或者thread.join()或者发出I/O请求时,JVM会把当前线程设置为阻塞状态,当sleep结束、join线程终止、IO处理完毕,则线程恢复。
WAITING
TIME_WAITING
超时等待状态,超时以后自动返回。
TERMINATED
终止状态。表示当前线程执行完毕。
线程状态代码示例
public class ThreadStatusDemo {
public static void main(String[] args) {
//TIME_WAITING
new Thread(()->{
while(true){
try {
TimeUnit.SECONDS.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
},"Time_Waiting_Thread").start();
//WAITING
new Thread(()->{
while(true){
synchronized (ThreadStatusDemo.class) {
try {
ThreadStatusDemo.class.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
},"Wating_Thread").start();
//BLOCKED
new Thread(new BlockedDemo(),"Blocke01_Thread").start();
new Thread(new BlockedDemo(),"Blocke02_Thread").start();
}
public static class BlockedDemo extends Thread{
@Override
public void run() {
synchronized (BlockedDemo.class){
while(true){
try {
TimeUnit.SECONDS.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
}
}
运行之后,通过右击class文件,show in terminal
jps
jstack 15836
TIME_WAITING
WAITING
BLOCKED
线程的终止 interrupt
当子线程中有while(true) 之类无法中断的操作时,可以使用interrupt中断子线程。
stop
stop()结束一个线程时,并不保证线程的资源正常释放,stop()已经过期
thread.interrupt()
将thread线程的终止标识设置为true。通知thread终止线程,至于什么时候中断,取决于线程自己
Thread.currentThread().isInterrupted()
获取当前线程终止标识,默认false
Thread.currentThread().interrupted()
线程终止标识置为初始状态 : false
代码示例
public class InterruptDemo {
public static void main(String[] args) throws InterruptedException {
Thread thread=new Thread(()->{
while(!Thread.currentThread().isInterrupted()){ //默认是false
// todo
}
// Thread.currentThread().interrupted(); //复位- 回到初始状态
});
thread.start();
TimeUnit.SECONDS.sleep(1);
thread.interrupt(); //把isInterrupted设置成true
}
}
注意:sleep 通过InterruptedException 中断线程
守护线程
在Java线程中有两种线程,一种是用户线程,另一种是守护线程。
守护线程是一种特殊的线程,特殊指的是当进程中不存在用户线程时,守护线程会自动销毁。
典型的守护线程的例子就是垃圾回收线程,当进程中没有用户线程,垃圾回收线程就没有存在的必要了,会自动销毁。
public class Daemon {
public static void main(String[] args) throws InterruptedException {
Thread thread = new Thread(new DaemonThread());
thread.setDaemon(true); // 子线程设置成守护线程,当前用户进程运行结束,子线程自动销毁
thread.start();
Thread.sleep(10);
}
public static class DaemonThread implements Runnable {
private int i;
@Override
public void run() {
while (true) {
i++;
System.out.println(i);
}
}
}
}
优先级
优先级分为1~10个级别,CPU会优先执行优先级较高的线程对象中的任务。如果设置优先级小于1或大于10,JDK抛出IllegalArgumentException。
JDK默认设置3个优先级常量,MIN_PRIORITY=1(最小值),NORM_PRIORITY=5(中间值,默认),MAX_PRIORITY=10(最大值)。
优先级具有继承性,比如线程A启动线程B,线程B的优先级与线程A是一样的。
优先级具有随机性,也就是说优先级高的线不一定每一次都先执行完成。