什么是进程?
我们这里学习进程是为了后面的线程做铺垫的。
一个程序运行起来,在操作系统中,就会出现对应的进程。简单的来说,一个进程就是跑起来的应用程序。
在电脑上我们可以通过任务管理器可以看到,跑起来的应用程序有哪些,同时也是每一个的进程。
在操作系统中,我们常常使用PCB这样的结构体来描述进程,pcb中包含了许多重要的信息,此处不做过多的讨论。
在pcb中最核心的就是,其中包括了很多的内存指针,该指针,会根据操作系统的操作来指向所要进行的资源。
如图:
上图就是,关于操作系统的流程(cpu,pcb,硬件等)。
在一个cpu中包括了很多的核心,一个核心只能进行一个进程。一个核心在不同的时刻可以进行不同的进程。
在这里pcb也提供许多的属性。
1.状态
就绪状态:就如同生活中随叫随到的这种状态,称为就绪状态。
阻塞状态:简单来说就是发生了阻塞,不能及时使用。
2.优先级
优先级:对一个程序的资源分配不均衡,消耗的时间有多有少,这种存在优先级的。
3.上下文
上下文:这里的上下文就如同字面的意思,上下要对应,不能逻辑不通。
4.记账信息
记账信息:这里延续了上面的优先级,因为分配资源的问题,我们这里要用表格来记录。
以上的几种属性就是pcb支持进程调度的几种属性。
线程的叙述和在idea上的实现方法
我们这里引入线程就是为了解决,进程创建开销比较大的问题。
线程开销比较小,会省很大的成本。
一个进程包括了多个线程。一个cpu的核可以运行多个线程。
线程具有并行和并发两种特性。
并行:就是指同一时刻可以进行多个任务。
并发:就是指不同的线程可以同时进行。
线程的实现
第一种方法:自己写一个类继承Thread类,重写run方法。
如代码:
package thread;
class MyThread extends Thread{
@Override
public void run() {
for(int i = 0; i < 100; i++){
System.out.println("hello Thread");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
}
}
public class Deom1{
public static void main(String[] args) {
Thread t = new MyThread();
t.start();
for (int j = 0; j < 100; j++){
System.out.println("hello main");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
}
}
如代码我们可以看到,上面有两个打印,我们来看一下效果。
如图:
我们可以看到,上面的结果打印是间断的不是连续的,所以这里可以说明,线程是并发执行的。
这上面的run方法就是该线程要执行的东西。
第二种方法:实现Runnable 。
如代码:
package thread;
class MyRunnable implements Runnable{
@Override
public void run() {
for(int i = 0; i < 100; i++){
System.out.println("hello Thread");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
}
}
public class Dome2 {
public static void main(String[] args) {
Thread t = new Thread(new MyRunnable());
t.start();
for (int j = 0; j < 100; j++){
System.out.println("hello main");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
}
}
这里的结果和上面的结果是一样的。
这里在实列t对象的时候,直接new的一个Thread ,里面又new的自己写的类,这样实现的,这个接口里面,包含了Thread的run方法。
第三种方法:运用匿名内部类
如代码:
package thread;
public class Deom3 {
public static void main(String[] args) {
Thread t = new Thread() {
@Override
public void run() {
for(int i = 0; i < 100; i++){
System.out.println("hello Thread");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
}
};
t.start();
for (int j = 0; j < 100; j++){
System.out.println("hello main");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
}
}
这里呢我们new的Thread相当于一个匿名的子类。
重写了run方法。
其运行的结果和第一种是一样的。
第四种方法:lambda表达式
如代码:
package thread;
public class Deome4 {
public static void main(String[] args) {
Thread t = new Thread(()-> {
for(int i = 0; i < 100; i++){
System.out.println("hello Thread");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
});
t.start();
for (int j = 0; j < 100; j++){
System.out.println("hello main");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
}
}
这里的lambda表达式,就相当于一个匿名的函数,用完就丢,平替了重写的run方法。
其运行结果和第一种一样。
在这所有的方法上面我们都使用了sleep方法,目的是让打印速度减慢,可以看到并发的效果。
以上就是线程的几种的实现方法。后面还会学习其他的。