【Java多线程与并发】- 01进程相关概念

线程的相关概念

一、进程与线程

进程(progress):官方的解释是计算机中的程序关于某数据集合上的一次运行活动,是操作系统进行资源分配

​ 与调度的基本单位,通俗来理解就是,Ctrl+Alt+Del,操作系统中所运行的一个程序。

线程(thread):线程是进程的一个执行单元,一个进程至少包含一个线程,所以可以有多个线程。

二、主线程与子线程

主线程:JVM里面会包含一个专门执行main方法的线程,就是主线程,所以主线程就是执行main方法的线程。

子线程:线程与线程直接会有着多种联系,不是独立存在的,所谓子线程可以理解为套娃,在A线程里面创建了B线程

​ 那么B线程就是A的子线程,也可以继续在A线程里面继续创建属于A的子线程。

三、串行、并行、并发

​ 为了更好理解表达,先假设有三个任务,A、B、C

串行:只有一条通道,A、B、C 需要一个一个的按序执行。

并行:在任务A 等待的时候,开始执行B任务,在B任务等待的时候开始执行C任务。

并发:三个任务同时开始同时执行,一般都是多核操作。

请添加图片描述

四、创建线程

1、以继承Thread类的形式创建

public class test01_ThreadCreateByExtend {
    public static void main(String[] args) {
        System.out.println("JVM启动main线程,执行了main方法");
        MyThread myThread = new MyThread();
        myThread.start();
        System.out.println("main后面其他的代码");
    }
}

class MyThread extends Thread {
    @Override
    public void run() {
        System.out.println("调用了子线程的Run方法");
    }
}

打印结果为

JVM启动main线程,执行了main方法
main后面其他的代码
调用了子线程的Run方法

注意:1.调用线程对象的**start()**方法,不意味着此线程开始运行,start方法是一种请求,请求JVM运行线程,真正执行要由

线程调度器(Scheduler)决定。

​ 2.当线程被调用就会执行run()方法

​ 3.线程执行顺序随机

​ 4.多线程执行结果与代码顺序无关

案例:多线程的随机性代码演示

public class test01_RandomOfThread {
    public static void main(String[] args) {
        MyThread2 myThread2 = new MyThread2();
        myThread2.start();
        
        //同Thread对象里面的方法
        for (int i = 1; i <= 10; i++) {
            System.out.println("Main---"+i);
            int time = (int) (Math.random()*1000);
            try {
                Thread.sleep(time);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}
class MyThread2 extends Thread {
    @Override
    public void run() {
        for (int i = 1; i <= 10; i++) {
            System.out.println("Thread2---"+i);
            int time = (int) (Math.random()*1000);  //定义一个随机数
            try {
                Thread.sleep(time);  //让线程休眠 随机时间
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}

打印结果 每次都不相同,以此证明多线程的随机性

Main---1
Thread2---1
Main---2
Thread2---2
Thread2---3
Thread2---4
Thread2---5
Main---3
Thread2---6
Thread2---7
Main---4
Thread2---8
Main---5
Main---6
Thread2---9
Thread2---10
Main---7
Main---8
Main---9
Main---10

2、通过实现Runnable接口创建线程

注:用到了动态代理

public class test01_ThreadCreateByRunnable {
    public static void main(String[] args) {
        MyRunnable myRunnable = new MyRunnable();
        Thread thread = new Thread(myRunnable);
        thread.start();
    }
}
class MyRunnable implements Runnable {

    @Override
    public void run() {
        System.out.println("我是MyRunnable -- 通过实现Runnable接口创建");
    }
}

五、线程的常用方法

1、线程的currentThread()方法

案例:打印出以下线程在对应代码位置的线程名字

public class test01_currentThread {
    public static void main(String[] args) throws InterruptedException {
        MyCurrentThread myCurrentThread = new MyCurrentThread();
        myCurrentThread.start();
        Thread.sleep(1000);

        Thread tt = new Thread(myCurrentThread);
        tt.start();
    }
}
class MyCurrentThread extends Thread {
    public MyCurrentThread() {
        System.out.println("构造方法---Thread.currentThread  "+Thread.currentThread().getName());
        System.out.println("构造方法---this.getName  "+this.getName());
    }

    @Override
    public void run() {
        System.out.println("run方法---Thread.currentThread  "+Thread.currentThread().getName());
        System.out.println("run方法---this.getName  "+this.getName());
    }
}

打印结果如下

构造方法---Thread.currentThread  main
构造方法---this.getName  Thread-0
run方法---Thread.currentThread  Thread-0
run方法---this.getName  Thread-0
run方法---Thread.currentThread  Thread-1
run方法---this.getName  Thread-0

解析:逆向分析–> 控制台共打印了6条语句

分辨方法:当前线程就是 谁调用了方法 就是谁

​ 第一条:程序从main方法入口,此时只有main线程,初始化子线程myCurrentThread时,main线程会调用它的构造方法

​ 所以,刚进入构造器的第一条线程是main线程。

​ 第二条:同样是在构造器里面,但是 调用的是this,也就是它自己本身,它本身就是一个线程对象,所以会打印出自己。

​ 第三条:程序继续执行,调用了myCurrentThread的start方法,线程被调用了,线程调度器就会去执行它的run方法,此时线程已 经被创建调用,所以再打印线程的名字,那就是它自己当前线程

​ 第四条:this 同样指向它自己

​ 第五条:程序继续执行,又创建了一个新的线程tt,但此线程与默认初始化的线程不同,把myCurrentThread作为参数传递

​ 到新的线程里,参数所需的是一个runnable对象,Runnable对象我们提到了,需要重写它的run方法,所以此新线

​ 程的run方法就是我们刚刚myCurrentThread的run方法,同样的执行完start方法后,新的线程被创建,那么调用run

​ 线程就是tt新线程

​ 第六条:涉及到新的线程里面的run方法,不过,此对象就是我们传递的myCurrentThread,所以this就是子线程1号的名字。

2、线程的isAlive方法

作用:isAlive方法可以判断当前线程是否处于活动状态

案例:查看线程是否处于活动状态

public class test01_isAliveMethod {
    public static void main(String[] args) {
        ThreadIsAlive thread = new ThreadIsAlive();
        System.out.println("Main方法里面 is Alive  "+thread.isAlive());
        thread.start();
        System.out.println("Main 后面 is Alive  "+thread.isAlive());
    }
}
class ThreadIsAlive extends Thread{
    @Override
    public void run() {
        System.out.println("run方法里面 is Alive  "+this.isAlive());
    }
}

打印结果

Main方法里面 is Alive  false
Main 后面 is Alive  true
run方法里面 is Alive  true

3、线程的sleep休眠

作用:调用Thread.sleep(ms)可以使当前的线程休眠一段时间

案例:计时器

public class test01_sleepThread {
    public static void main(String[] args) throws InterruptedException {
        int count = 5;
        while (true){
            if(count<=0){
                break;
            }
            System.out.println("倒计时:"+count);
            Thread.sleep(1000);
            count--;
        }
        System.out.println("结束!");
    }
}

4、线程的getId方法

作用:能够获取线程的唯一标识

5、线程的yield方法

作用:进行线程让步

案例:对子线程进行线程让步,进行与main线程的耗时对比

public class test01_yieldThread {
    public static void main(String[] args) {
        YieldThread thread = new YieldThread();
        thread.start();

        long begin = System.currentTimeMillis();
        int sum = 0;
        for (int i = 0; i < 1000000; i++) {
            sum+=i;
        }
        long end = System.currentTimeMillis();
        System.out.println("main线程所有时间 "+(end-begin));
    }
}

class YieldThread extends Thread {
    @Override
    public void run() {
        long begin = System.currentTimeMillis();
        int sum=0;
        for (int i = 0; i < 1000000; i++) {
            sum+=i;
            Thread.yield();
        }
        long end = System.currentTimeMillis();
        System.out.println("子线程所用时间 "+(end-begin));
    }
}

打印结果

main线程所有时间 4
子线程所用时间 712

6、线程的setPriority方法

作用:设置线程的优先级,在日常开发中很少使用,范围1~10

注意:

  • ​ 线程优先级本质上是给线程调度器一个提示信息,可以决定先执行那些线程,但不保证优先级高的一定先执行
  • ​ 优先级设置不当可能会导致线程饥饿
  • ​ 线程优先级具有继承性

7、线程的interrupt方法

作用:可以标识一个线程是否要被打断,并不是真正意义上的打断,需要配合isInterruptted方法使用

案例:配合interruptted方法,打断子线程的输出

public class test01_interrputThread {
    public static void main(String[] args) {
        InterruptThread thread = new InterruptThread();
        thread.start();
        for (int i = 0; i < 100; i++) {
            System.out.println("main线程 "+i);
        }
        thread.interrupt();  //标识打断子线程
    }
}

class InterruptThread extends Thread {
    @Override
    public void run() {
        for (int i = 0; i < 100; i++) {
            if(this.isInterrupted()){  //判断是否被打断,为真 就直接跳出循环
                break;
            }
            System.out.println("子线程线程 "+i);
        }
    }
}

打印结果

main线程 96
main线程 97
main线程 98
main线程 99
子线程线程 49

8、线程的setDaemon方法

作用:设置线程为守护线程

注意:Java线程分为 用户线程和守护线程,GC就是一个守护线程,守护线程不可单独使用,JVM中只有守护线程时,会自动退出

​ 在设置为main线程的守护线程时,main线程结束,其对应的守护线程也会被销毁

​ 设置守护线程的代码,一定要在start()方法之前,否则不生效

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值