先回顾以下上一篇文章的主要内容:
进程的概念:一个程序运行起来就是一个进程,进程是系统分配资源的基本单位.
操作系统通过先描述在组织的方法管理进程:通过PCB(程序控制快)结构体来把进程中的各种属性描述出来,通过链表把这些PCB组织起来.
PCB的核心属性:pid进程标识符.内存指针,指向该进程所依赖的指令和文件.文件描述表,该进程打开了那些文件.状态,优先级,记账信息,上下文.
接下来接着介绍线程,首先线程是什么呢?当前的CPU都是多核心CPU,都是通过多进程的编程模式进行编程的,可以把CPU的多个核心很好的利用起来.但是也存在一些问题,如果程序运行的运行关闭十分频繁,那么操作系统就需要频繁的创建/销毁进程.为了解决这一个问题,就有了线程这一该概念.线程:thread,也称为"轻量级进程".原因是创建/销毁的开销更小.线程可以理解为进程的一部分,一个进程中可以有多个线程.上节谈到了PCB结构体用来描述进程,这里从线程方面重新说明一下PCB的几个特性:
1.pid每个线程都是不一样的 2.内存指针,文件描述符,同一个进程的若干个线程是同一个.3.状态,上下文,优先级,记账信息.每个线程都有属于自己的属性.4.tgid 同一个进程的线程是一样的.
总结一下:同一个进程的若干个线程之间,是共用相同的内存资源和文件资源的.每个线程都是在CPU上独立调度运行.
为什么说线程比进程更加轻量?
原因是创建一个进程,必定涉及到资源分配/资源释放的过程.但线程是包含在进程中的,创建一个线程(除了第一个线程之外)就不需要涉及到资源分配/释放步骤了.因为进程中的线程是共用资源的.当然,一个进程中的线程也不是可以无限创建的,当进程中的线程太多时,线程调度的开销就会非常明显,程序的性能可能不升反降.还有就是多个线程共同完成某个任务,会涉及到线程安全问题.
线程,本身是操作系统提供的.操作系统提供了API对让我们操作线程.JVM就对操作系统api进行了封装,提供了Thread类,表示线程.接下来介绍一下多线程代码如下:
package Demo1;
//第一种方法就是直接写,通过Thread类实现多线程
class MyThread extends Thread{
public void run(){
while(true) {
System.out.println("hello thread");
}
}
}
public class Demo1 {
public static void main(String[] args){
Thread t=new MyThread();
t.start();
while(true){
System.out.println("hello thread");
}
}
}
这就是一种多线程的写法
可以看到 Thread 和main 两个线程.多个线程的调度是无序的,在操作系统内部也称为"抢占式执行".任何一个线程,在执行到任何一个代码的过程中,都可能被其他线程抢占掉他的CPU资源.
上述代码中,run只是描述了线程要干啥任务.t.start()会调用操作系统的api在内核中创建PCB,并且加入到链表中.进一步的系统调度到这个线程之后,就会执行上述run方法中的逻辑.
还可以通过Runnable接口创建线程:
class MyRunnable implements Runnable{
@Override
public void run() {
System.out.println("hello Thread");
}
}
public class Demo2{
public static void main(String[] args){
Thread t=new Thread(new MyRunnable());
t.start();
System.out.println("hello main");
}
}
还可以通过使用匿名内部类的方式来创建进程
public class Demo3 {
public static void main(String[] args){
Thread t=new Thread(){
public void run(){
System.out.println("hello Thread");
}
};
t.start();
System.out.println("hello,main");
}
}