Java程序,进程,线程
程序:通俗而言就是你编写的静态的代码;
进程:程序在电脑上执行的过程,同一个程序可以有不同的进程,进程之间不会争夺内存资源;
线程:进程内部的单一的一个顺序控制流.一个进程在执行过程中,可以有多个独立的线程,线程之间会共享和互相争用资源;
例如: 12306买票系统一运行,就是一个进程,而我们每一个人去买票,就是一个独立的线程
一个类继承了Thread类,该类就是线程类,创建该类对象就是线程对象.
当Java虚拟机执行程序的时候,会先找到主线程,而主线程的入口方法就是主方法;
虚拟机为主线程开辟空间,叫做主线程栈,并为主线程分配PC指令寄存器,
线程的生命周期
分为五个阶段:
- 新建:线程的命名和线程的优先级设定必须在新建态;
命名:setName(); //不命名时,默认为Thread0,Thread1
优先级:setPriority(Thread.MAX_PRIORITY) ; //三个级别
10,5,1级,默认为5级,主方法为5级
- 就绪:利用start()方法可以使线程进入就绪态,
Java中允许多个就绪态的线程
- 运行:执行代码
- 阻塞:睡眠,锁池,等待池(wait()),从键盘缓冲区读取数据;
阻塞状态的线程,不论优先级的大小自动让出cpu
- 结束:主方法结束完,主线程死亡,其他线程的run方法执行完比之后死亡
当然其他线程也会导致另外线程的死亡
线程的执行过程
1.一个线程也是一个对象,所以当一个线程类创建其线程对象的过程,就是线程的新建状态(一般在主线程的主方法内);
2.当该线程对象.start()时,线程处于就绪态状态,此时该线程就可以征用处理机了
(就绪池:可以有多个就绪状态的线程);
3.当处理机空闲时,就会执行就绪态的线程,此时的线程就从就绪状态变为运行状态(就是运行run()方法里的代码的过程),但是到底调度那个线程,就取决于调度策略了;
4.那么当一个线程遇到sleep(),锁,等情况,放弃处理机时,从运行态到阻塞态,当该线程睡醒了,或者有能力再度征用处理机时,就会从阻塞态转变为就绪态;
5.当运行状态的线程,遇到yield(),或者时间片选机制时 会从运行态到就绪态
6.当主线程的主方法执行完,或者其他线程的run()方法,或者强行死亡,就变成了死亡状态,将其所占用的所有资源全部释放
代码展示
//线程类Mathine,继承Thread,在Java.lang包下
public class Mathine extends Thread{
//Override
public void run(){
for ( int a=0;a<10;a++){
//currentThread()获取线程的地址
System.out.println(currentThread().getName()+":"+a);
try {
sleep(100);//睡眠100毫秒
}catch (InterruptedException e) {throw new RuntimeException(e);
}
}
}
//主线程的入口方法就是主方法
public static void main(String[] args) {
Mathine mathine1 = new Mathine();
Mathine mathine2 = new Mathine();
//命名,
//不命名的话默认为Thread0,Thread1
mathine1.setName("m1");
mathine2.setName("m2");
//设置优先级1,5,10,默认是5;
mathine1.setPriority(Thread.MAX_PRIORITY);
mathine2.setPriority(Thread.MIN_PRIORITY);
System.out.println("Priority of m1:"+mathine1.getPriority());
System.out.println("Priority of m2:"+mathine2.getPriority());
//mathine1,mathine2由新建进入就绪态
mathine1.start();
mathine2.start();
mathine1.run();
}
}
运行结果是随机的:
调度策略
Java的调度策略:
1. 在同优先级的情况下是随机的;不同优先级的,谁高谁先
2. 如果该线程不主动退出,则一直执行
windowsdoc的调度策略:
1. 先到先得
2. 时间片轮转 //有运行态变为阻塞态
尴尬的是:Java最大的优点之一跨平台,在线程这块行不通,线程的调度依赖于底层的操作系统,所以导致在Java的多线程中,线程的执行顺序是随机的
执行过程
每个线程都会在栈中有他的线程栈空间,
在上图代码中:
1.虚拟机进入主方法后,在栈区开辟主线程栈主方法帧,
2.Mathine mathine1 = new Mathine();
Mathine mathine2 = new Mathine();
在堆区开辟对象空间(属性和方法)
3.mathine1.run();
在主线程主方法的run方法栈中给成员变量a=0,断点,引用开辟空间
4.当主线程sleep之后,主线程进入阻塞态,让出处理机;mathine1线程由就绪态转变为运行态 ;在mathine1线程的run方法栈中开辟空间存放变量a=0…;
以此类推mathine2线程.