线程初步认识

Posted 无赖H4

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了线程初步认识相关的知识,希望对你有一定的参考价值。

认识线程(Thread)

概念

  • 线程属于进程的组成(每个进程中至少有一个线程(主线程),也可以有多个线程)
  • 线程是os进行调度的最小单位。
  • 进程是系统分配资源(包括CPU)的最小单位,线程是系统调度(CPU分配)的最小单位

什么情况下需要线程

  • 原有的执行流(调度单位)因为某些事件堵塞了,同时我们还需要运行一些其他的代码时
  • 需要一些调度单位加速我们的代码运行速度

创建Java线程

Thread的几个常见属性

属性获取方法说明
IDgetId()唯一标识,不同线程不会重复
名称getName()调试可能用到
状态getState()当前所处的状态
优先级getPriority()优先级高的更容易调度到
是否后台线程isDaemon()JVM会在一个进程的所有非后台线程结束后,才会停止运行
是否存活isAlive()是否存活,简单理解为:run方法是否运行结束了
是否被中断isInterrupted()线程中断

如何创建Java线程

  • Thread类——每个Thread对象都是代表一个线程
  • Runnable接口——每个Runnable对象都是一个任务

Thread类是JVM用来管理线程的类,每个线程都有唯一的Thread对象关联。

例子:

  • 线程继承自Thread类,并且重写Run方法。
 class MyThread extends Thread {
    @Override
    public void run() {
        while (true) {
            System.out.println("另一个线程");
        }
    }
}

public class Demo1 {
    public static void main(String[] args) {

        MyThread t = new MyThread();
        t.start();

        while (true) {
            System.out.println("主线程");
        }
    }
}
  • 实现Runnable接口,重写其Run方法,实例化一个Runnable对象,构造Thread对象时,将Runnable对象传入。
class MyRunnable implements Runnable {

    @Override
    public void run() {
        //while (true) {
            System.out.println("另一个线程");
        //}
    }
}

public class Demo2 {
    public static void main(String[] args) {

        MyRunnable myRunnable = new MyRunnable();
        Thread thread = new Thread(myRunnable);

        thread.start();
       // while (true) {
            System.out.println("主线程");
       // }
    }
}

Thread对象也可以当做Runnable对象使用
多线程的现象具有随机性,随机性的来源——调度机制

start() vs run()

重写run方法,是提供线程需要做的事情,调用start是真正独立执行。启动线程需要调用start方法

Thread类常见的构造方法:

方法说明
Thread()创建线程对象
Thread(Runnable target)使用Runnable对象创建对象
Thread(String name)创建线程对象,并命名
Thread(Runnable target,String name)使用Runnable对象创建线程对象,并命名

线程中断

绝大多数我们的线程代码,是跑在一个死循环中的
1、通过一些共享数据让其停止
2、Thread类提供了方法,使得其停止
可以认为,每个Thread对象中,都有一个类似变量让其停止。

调用方法

其他线程可以调用 . interrupt();
在需要停止的线程内部,通过调用 boolean Thread.interrupted();
在其内部可能有两种状态:
1、调用类似的sleep方法,处于阻塞状态,会收一个InterruptedException异常,表示需要其停止。
2、处于就绪状态,正在执行代码,
Thread.interrupted()返回true,表示需要其停止

class MyThread2 extends Thread {
    @Override
    public void run() {

        while (!Thread.interrupted()) {
            try {
                TimeUnit.SECONDS.sleep(1);
            } catch (InterruptedException e) {
                e.printStackTrace();
                break;

            }
            System.out.println("子线程");
        }
    }
}

public class Demo2 {
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);

        MyThread2 myThread = new MyThread2();
        myThread.start();

        sc.nextLine();
        myThread.interrupt();
    }
}

只能建议停止,不能强制停止
Thread.interrupted()读取一次后便会清除其中断标志
使用 .isInterrupted()在判断指定线程的中断标志设置不清除中断标志。

等待一个线程

有时候,我们需要等待一个线程完成它的工作后,才能进行下一步工作,例如:甲线程等待乙线程结束。
使用 . join();
例如:

class MyThread extends Thread {
    @Override
    public void run() {
        try {
            TimeUnit.SECONDS.sleep(10);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

public class Demo {
    public static void main(String[] args) throws InterruptedException {
        MyThread myThread = new MyThread();
        myThread.start();
        for (int i = 0; i < 5; i++) {
            System.out.println(i);
        }

        myThread.join();
        for (int i = 0; i < 5; i++) {
            System.out.println(i);
        }
    }
}

线程的状态

理论上的线程状态分为:初识、就绪、运行和停止
在这里插入图片描述
实际上在Java中分为:NEW、RUNNABLE、TERMINATED、BLOCKED、WAITING、TIMED_WAITING
在这里插入图片描述

Thread.isXXX()

alive:那些状态是alive的?
RUNNABLE、TERMINATED、BLOCKED、WAITING、TIMED_WAITING
(就绪、运行、阻塞)

daemon: 后台线程 vs 默认
后台线程会执行一些不影响的主流线程,但需要默默工作的事情:1、垃圾回收机制、2、听歌背后的下载线程
设置:
后台线程:thread.setDaemon(true);
前台线程:thread.setDaemon(false);

什么时候一个JVM进程结束:
所有前台线程都运行结束(1、后台线程不影响,2、和是不是主线程无关)

Thread中常见静态方法

1、Thread.sleep(毫秒); == TimeUtil.MILISECONDS.sleep(毫秒);
2、Thread thread = Thread.currentThread();
返回调用该方法的线程的对象的引用
3、Thread.yield(); 主动放弃CPU;
例如:

public class ThreadYiled {
    static class Mythread1 extends Thread {

        Mythread1(String name){
            super(name);
        }
        @Override
        public void run() {
            while (true){
                if (getName().equals("张三")){
                //放弃CPU
                    Mythread1.yield();
                }
                System.out.println(getName());
            }
        }
    }

    public static void main(String[] args) {

        Mythread1  mythread1 = new Mythread1("张三");
        mythread1.start();

        Mythread1  mythread2 = new Mythread1("李四");
        mythread2.start();
    }
}

观察线程状态工具

jconsole工具 官方安装jdk中自带
1、启动程序(有线程在跑的程序)
2、打开jconsole工具
(在jdk安装目录下,bin目录下面的 jconsole.exe)
3、选择要观察的程序

JVM运行时内存区域划分

  • 堆区——存对象——属性 共享的

  • 方法区——存属于类的信息(类中的方法(字节码),类中的静态属性) 共享的

  • 运行时常量池 共享的

  • 栈——栈帧,描述方法一次执行的过程——局部变量(包括形参) 私有的

  • PC程序计数器——当前线程下一条要执行的指令地址 私有的

进程是资源分配的最小单位——分配给进程的内存空间没有被特殊处理过,都是线程之间共享的

我们可以推导出:
局部变量:线程私有
属性:线程共享
静态属性:线程共享

前提:线程可以通过自己拥有的变量访问到这些属性

以上是关于线程初步认识的主要内容,如果未能解决你的问题,请参考以下文章

线程初步认识

JAVA-初步认识-第十二章-JVM中的多线程分析

Scrapy的初步认识

一线程的初步认识

JAVA-初步认识-第十四章-多线程(守护线setDaemon)

JAVA-初步认识-第十四章-多线程-停止线程方式-定义标记