package com.demo;
/**
* 进程:正在运行的程序叫做进程,进程负责了这个程序的内存空间分配,代表了内存中的执行区域;
*
* 问题:Windows号称是多任务的操作系统,那么Windows是同时运行多个应用程序吗?
* 从宏观角度:从感知和能看得到的现象来说,确实是同时运行多个应用程序的;
* 从微观角度:由于CPU分时机制的作用,使每个进程都能循环获得自己的CPU时间片,但因为轮换速度非常快,
* 所以看起来好像所有的程序都在同时运行一样;
*
* 线程:线程在一个进程中负责了代码的执行,就是进程中一个执行路径;
* 多线程:就是在一个进程中多个执行路径同时执行;
*
* 运行任何一个Java程序,jvm在运行的时候都会创建一个main线程,来执行main方法中的所有代码;
*
* 问题:一个java程序至少有几个线程?
* 至少有两个线程,一个是主线程负责main方法代码的执行,一个是垃圾回收器线程,负责垃圾的回收;
*
* 多线程的好处:
* 1、解决了一个进程能同时执行多个任务的问题;
* 2、提高了资源的利用率,而不是提高效率;
* 多线程的弊端:
* 1、对线程进行管理要求额外的CPU开销,增加了CPU的负担;
* 2、降低了一个进程中线程的执行效率;
* 3、引发了线程安全问题;当多个线程需要对公有资源进行操作时,后一个线程往往会修改掉前一个线程保存的数据;
* 4、出现了死锁现象;即较长时间的等待或资源竞争;
*
* 线程的创建有两种方法:
* 方法一:
* 1、自定义一个类继承Thread类;
* 2、重写Thread类的 run() 方法;
* 问题:为什么要重写 run() 方法?
* 每个线程都有自己的任务代码,jvm创建的主线程的任务代码就是 main() 方法中的所有代码,
* 而自定义线程的任务代码就是run() 方法中的所有代码。
* 3、创建Thread的子类对象,并且调用 start() 方法开启线程;
* 注意:一个自定义线程一旦开启,就会执行 run() 方法中的任务代码;run() 方法不能直接调用,
* 因为直接调用就相当于调用了一个普通方法,并没有开启线程;
*
* 线程的生命周期:如下图所示:
* CPU的等待资格:具有CPU等待资格的线程,表示CPU在切换的时候有可能执行的线程;
* CPU的执行权:具有CPU执行权的线程,表示CPU正在执行的线程;
*
* 1、Demo1 d = new Demo1():当线程对象被 new 出来的时候,线程处于“创建状态”,该状态下的线程不具备任何资格;
* 2、d.start():调用线程的 start() 方法,线程进入“可运行状态”,该状态的线程具备CPU等待资格,不具备CPU执行权;
* 3、当线程得到CPU的执行权,进入“运行状态”,此时线程具备CPU的执行权,也具备CPU的等待资格;
* 4、如果线程在执行过程中被抢走了CPU的执行权,线程将重新进入“可运行状态”;
* 5、当线程执行完任务代码后,就进入了“死亡状态”。
* 6、除了 “创建状态->可运行状态->运行状态->死亡状态”,这四种正常状态之外,线程还存在一种“临时阻塞状态”;
* 当“运行状态”下的线程执行了 sleep() 方法或者 wait() 方法,线程就会进入“临时阻塞状态”;
* 如果线程是调用了sleep()方法进入的“临时阻塞状态”,那么一旦超过指定的睡眠时间,就会重新进入“可运行状态”;
* 如果线程是调用了wait()方法进入的“临时阻塞状态”,那么需要其他线程唤醒该线程,才可以重新进入“可运行状态”;
*
*/
public class Demo1 extends Thread {
@Override
public void run() {
// 执行自定义线程的任务代码
for (int i = 0; i < 100; i++){
System.out.println("自定义线程: " + i);
}
}
public static void main(String[] args) {
// 创建自定义线程对象
Demo1 d = new Demo1();
//d.run(); // 没有开启线程,只是在主线程中调用了一个普通方法
d.start(); // 启动线程
for (int i = 0; i < 100; i++){
System.out.println("main线程: " + i);
}
}
}