javaday26 进程和线程

1、进程和线程

1.1、进程

代表内存中正在运行的程序,计算机会将资源合理的分配每个进程

进程是系统运行一个应用程序的基本单位

当然启动一个应用程序,会有一个或多个进程同时被创建

1.2、线程

线程是进程中的一个代码执行单元

负责将当前进程中的代码程序执行

一个进程有一个或多个线程

每一个进程都会向计算机抢占运行所需的资源,而这些资源最终是要分配给进程中的线程。

当我们使用Java去运行一个Java程序的时候,会启动JVM,而JVM相当于计算机来说,它也是一个应用程序,所以会同时启动进程和JVM对应

1.3、并发和并行

  • 线程并发执行,是指在同一个时间段了,多个线程使用同一个cpu,并交替运行
  • 线程并行执行,是指同一个时刻,多个线程各自使用不同的CPU,同时进行程序

我们开发程序,都是按照单核CPU来考虑

多核CPU可以提高程序运行速度,但基本不会影响我们代码的设计和实现的。

1.4、时间片

时间片—一个线程允许使用CPU运行的时间

如果时间片结束,那么这个线程必须就要暂停运行。

这是因为线程是交替式的使用CPU。

因为线程交替运行的速度很快,所以我们就会觉得这两个线程同时运行

1.5、调度

当多个线程同时使用一个CPU的时候,就需要相应的算法来控制线程获取CPU时间片的方式,从而使得线程可以按照某种顺序来使用CPU。

常见的调度方式:

  • 时间片轮转

    所有线程轮流使用CPU的使用权,平均分配每个线程占用CPU的时间

  • 抢占式调度

    系统会优先让优先级高的线程使用CPU(优先级高不代表一定可以抢到CPU,只是抢到的概率相对而言比较高),如果线程的优先级相同,那么就是随机选择一个线程获取当前CPU的时间片

JVM中的线程,用的都是抢占式

1.5、main线程

在启动JVM加载一个类的时候,JVM会创建一个名字叫做main的线程,来执行类中的main方法

  1. 当使用Java运行一个类的时候,会先启动JVM
  2. 首先通过JVM的类加载子系统,将相应的类信息加载到方法区(静态成员在类加载的时候也会一起加载到方法区)
  3. 接着JVM会创建并启动main线程
  4. main线程会加载main方法,并且执行main方法中的代码,输出相应的结果
  5. 在mian方法中的代码执行完毕,main方法弹栈,main线程结束,JVM也随之停止

注意,这是只有main一个线程的时候的情况,如果存在多个线程,那么JVM就会等到所有线程结束才会停止

1.6、线程的创建和启动

java.lang.Thread 是java中的线程类,所有的线程对象都必须是Thread类或其子类的实例

每个线程的作用,就是完成开发人员给它指定的任务,实际上就是执行一段开人员指定的代码

线程最重要的就是run()方法中的代码,这也是我们所要关注的

通过继承的Thread类中来创建并且启动一个新的线程

  1. 定义Thread类的子类(可以是匿名内部类),并重写Thread类中的run方法,run方法中的代码就是线程的执行任务
  2. 创建Thread子类的对象,这个对象就代表了一个要独立运行的新线程
  3. 调用线程对象的start方法来启动该线程
public class Test {

    public static void main(String[] args) {
		
        //2.创建线程类对象
        Thread t = new MyThread();
        //启动线程才会抢占CPU的时间片
        //3.调用start方法启动线程
        t.start();

    }


}

//1.子类继承父类Thread,并重写run方法(指定线程的执行任务)
class MyThread extends Thread{
    @Override
    public void run() {
//线程启动以后要执行的代码
        for (int i = 0; i < 10; i++) {
            System.out.println("hello world");
            try {
                //可以让当前执行代码的线程睡眠1000毫秒,休眠期间不会让出CPU
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }

    }
}

//匿名内部类的方式
public class Test {

    public static void main(String[] args) {

        Thread t = new MyThread(){
            @Override
            public void run() {

                for (int i = 0; i < 10; i++) {
                    System.out.println("hello world");
                    try {
                        Thread.sleep(1000);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }

            }
        };
        
        t.start();

    }


}

main线程在执行main方法的过程中,创建并启动了其他线程,并且其他线程启动后,和main线程就没有关系了,这时候main线程和其他线程都是自己独立的运行,并且他们是要争夺CUP的时间片(使用权)的

在JVM中,方法区和堆是所有线程共享的,但栈和PC计数器是每一个线程独有的

线程对象被创建出来之后,只是一个普通的对象,只有当调用了start()方法之后,才算是一个创建了新的线程

线程在启动之后,就会开始抢占时间片,并且自动运行run方法,如果run方法没有重写,那么就会父类的run方法

多线程相比单线程的优势就在于 可以提高程序的运行速度

1.7、Runnable接口

给一个线程对象指定要执行的任务,除了继承Thread类后重写run方法之外,还可以利于Runnable接口来完成线程任务的指定

Runnable接口中只有一个抽象方法,就是run方法

我们可以通过实现这个接口或者使用匿名内部类来实现run方法,

在Thread类中的构造器就有一个构造器就是传一个Runnable接口的实现类对象进来

例如

public class Test {

    public static void main(String[] args) {
		
        //Runnable接口的实现类中,重写了run方法,指定线程的执行任务
        Runnable run = new Runnable() {
            @Override
            public void run() {
                for (int i = 0; i < 10; i++) {
                    System.out.println("hello world");
                    try {
                        Thread.sleep(1000);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }
        };
		
        //创建线程对象,指定执行任务
        Thread t = new Thread(run);

        t.start();

    }

}

实现Runnable接口比继承Thread类所具有的优势:

  1. 可以把相同的一个执行任务(Runnable接口的实现),交给不同的线程对象去执行(这个使用继承也是可以实现)
  2. 可以避免java中的单继承的局限性。
  3. 线程和执行代码各自独立,实现代码解耦

1.8、线程的名字

Thread.currentThread().getName(); 通过这个方法可以获得当前线程的名字

注意

public static void main(String[] args){
    show();
} 
public static void show(){
    System.out.println(Thread.currentThread().getName());
} 

结果
    main

这是因为是在main线程中调用main方法,而main方法中又调用了show()方法,所以还是在main线程中

main线程是程序的主线程

默认情况下,主线程中,创建出的线程,它们的都会有一个默认的名字:

public Thread() {
    init(null, null, "Thread-" + nextThreadNum(), 0);
}

其中,"Thread-" + nextThreadNum() 就是在拼接出这个线程默认的名字,Thread-0 Thread-1 Thread-2等等

当然我们也可以自己指定线程的名字

Thread t = new Thread("t线程");

//或者
Thread t = new Thread(new Runnable(){
    public void run(){
        //执行任务
    }
    //在创建线程的时候指定其名字不能够再线程启动以后再去执行
},"t线程");


//或者
Thread t = new Thread();
t.setName("t线程");
//只有调用start才会启动线程

1.9、线程的分类

java中,线程可以分为:

  • 前台线程,又叫做执行线程、用户线程
  • 后台线程,又叫做守护线程、精灵线程

前台线程:

这种线程专门用来执行用户编写的代码,

前台线程—main,开发人员自己编写线程,JVM是否关闭取决于前台线程是否执行完

后台线程:

这种线程是用来给前台线程服务的,给前台线程提供一个良好的运行环境,

后台线程—给前台的线程提供良好的运行环境,内存环境,类加载环境等,JVM是否停止运行跟后台线程

当然也可以通过特定的方法使得开发人员编写的代码变成后台线程

public class Test {

    public static void main(String[] args) {


        Thread t = new Thread("t线程"){
            @Override
            public void run() {
                String name = Thread.currentThread().getName();
                for (int i = 0; i < 10; i++) {
                    System.out.println(name+": hello "+i);
                }
            }
        };
		
        //在启动线程之前,可以将其设置为后台线程,否则默认是前台线程
        t.setDaemon(true);

        t.start();


    }

}

1.10、线程优先级

线程的优先级使用int类型数字表示,最大是10,最小是1,默认的优先级是5。

当俩个线程争夺CPU时间片的时候:

  • 优先级相同,获得CPU使用权的概率相同
  • 优先级不同,那么高优先级的线程有更高的概率获取到CPU的使用权

setPriority()这个方法就是可以设置线程的优先级,要在线程启动之前设置好,里面传的参数只能是1~10的正正数。

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值