认识一下线程

简介: 认识一下线程

         1.线程的定义

                     2.线程和进程的区别和应用

            3.多线程的五种代码实现方式

                      1.使用继承Thread类,重写run方法实现

                           2.使用实现Runnable接口,重写run方法

    3.继承Thread类,使用匿名内部类

           4.实现Runnable,使用匿名内部类

 5.使用lambda表达式

         4.查看线程的方法


   5.Thread类的常见方法

6.Thread类常见的几个属性

1.什么是线程

线程是独立的执行流,进程包含线程,多个线程在进程中也是并发执行的,多个线程在CPU上调度执行的顺序是随机的


在Java中我们会采用多线程编程,为啥不采用多进程编程呢


操作系统提供了多进程的API,但是JDK并没有对这些API进行进一步封装,所以Java无法使用


,那么就采用多线程编程


线程和进程相比更加轻量,创建线程耗费的资源也更少


一个进程的多个线程之间共用同一份资源


1.内存资源


2.文件描述符表


只有在进程启动,创建第一个线程的时候,需要申请系统资源,之后的线程就不用了,进程之间互不影响,但是线程之间一旦有一个崩溃了,那么就可能导致其他线程也崩溃,导致整个进程崩溃


这个可能比较抽象,我来举个例子


比如CCtalk,我们点击运行,它是一个进程,里面的声音,画面等功能就是多线程,假如画面卡顿了,就有可能导致声音卡顿,甚至导致整个程序崩溃


来解释一下多个线程是并发执行的原因


这里的并发说的也是并发+并行


可以在多个CPU的多个核心同时执行


可以在一个CPU的一个核心上,进行快速调度运行


可以在一个CPU的多个核心上同时进行


其实操作系统调度的是线程,我们所说的进程调度是因为之前讨论的是进程只有一个线程的情况


说了这么多,我们来总结一下的进程和线程的区别


1.进程包含线程

2.进程有独立的内存资源和文件描述符表,同一个进程的多个线程之间,共享同一份内存地址和文件描述符表    

3.进程是操作系统资源分配的基本单位,线程是操作系统进程调度的基本单位

4.进程之间具有独立性,线程不具有独立性

5.创建线程比创建进程快

6.销毁线程比销毁进程快

7调度线程比调度进程快

下面来说一说线程的代码表现

线程其实是操作系统的概念,Java进一步对线程API进行封装,Java有个Thread类就是表示线程的,下面让我们用代码来看看

1.继承Thread类,重写run方法实现


package threading;
//继承Thread类,重写run方法
class MyThread extends Thread{
    @Override
    public void run() {
        System.out.println("hello t ");
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }
    }
}
public class ThreadDemo1 {
    public static void main(String[] args)  {
        Thread t = new MyThread();//向上转型
        //创建一个新的线程
        t.start();
        t.run();//注意,这个方法代表还是主线程里面的
        while (true) {
            System.out.println("hello main");
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
        }
    }
}


2.继承runnable接口,重写run方法

class MyRunnable implements  Runnable{
    @Override
    public void run() {
        while(true){
            System.out.println("hello t");
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
        }
    }
}
public class ThreadDemo2 {
    public static void main(String[] args) {
        MyRunnable runnable=new MyRunnable();
        Thread t=new Thread(runnable);
        t.start();
        while(true){
            System.out.println("hello main");
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
        }
    }
}

3.继承Thread类,实现匿名内部类


public class ThreadDemo3 {
    public static void main(String[] args)  {
        Thread  t=new Thread(){
            @Override
            public void run() {
               while(true){
                   System.out.println("hello t");
                   try {
                       Thread.sleep(1000);
                   } catch (InterruptedException e) {
                       throw new RuntimeException(e);
                   }
               }
            }
        };
        t.start();
        while(true){
            System.out.println("hello main");
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
        }
    }
}


4.继承runnable 接口,实现匿名内部类


public class ThreadDemo4 {
    public static void main(String[] args) {
     Thread t=new Thread(new Runnable() {
         @Override
         public void run() {
             while(true){
                 System.out.println("hello t");
                 try {
                     Thread.sleep(1000);
                 } catch (InterruptedException e) {
                     throw new RuntimeException(e);
                 }
             }
         }
     });
     t.start();
     while(true){
         System.out.println("hello main");
         try {
             Thread.sleep(1000);
         } catch (InterruptedException e) {
             throw new RuntimeException(e);
         }
     }
    }
}


5.使用lambda表达式


public class ThreadDemo5 {
    public static void main(String[] args) {
        Thread t=new Thread(()->{
            while(true){
                System.out.println("hello t");
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    throw new RuntimeException(e);
                }
            }
        });
        t.start();
        while(true){
            System.out.println("hello main");
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
        }
    }
}

我们有时候需要查看线程的状态,这时需要使用idea下的一个工具,方法如下


1.运行线程


2.打开Java所在文件目录,找到bin目录下的jconsole.exe,点击运行


C:\Program Files\Java\jdk1.8.0_192\bin,在我的电脑是这个路径,每个人的应该是不一样的


96ed0e47d6fa47c69648c74d0a6db01a.png

eb2a43246d4a480c89615b5874b0b30c.png

线程在跑的时候,就可以通过这个工具看到


Thread常见的方法


Thread()//创建线程对象


Thread(Runnable target)//继承runnable接口,创建线程对象


Thread(String name)//给线程起个名字,方便调试


Thread(Runnable target ,String name)//使用 Runnable 对象创建线程对象,并命名


起名字这个只是起个名字,开举个例子


49972cdad0a14d748cd421303c24837a.png


再次打开JDK下的jconsle查看

就是为了方便调试而已

Thread类的一些属性,线程有自己的状态,优先级,上下文,记账信息,id等,其实进程 的属性就是线程的,只是我们那个时候讨论的是只有一个线程的进程

ID                        getId()

名称                    getName()

状态                   getState()

优先级                getPriority()

是否后台线程     isDaemon()

是否存活             isAlive()

是否被中断             isInterrupted()

这一期就先聊前六个,中断放到下一期,这个比较复杂

先看id,每个线程都有自己的'id',这算自己的身份标识

name就是每个线程的名字了

状态,举个例子


20842b923512478b9c9ad094b088968b.png


现在的代码是runnable状态,也就是正在运行

对于优先级和状态后后期进行详细讲解

看看isDaemon()方法,结果默认是false,那就是后台线程,如果改为true,那就是前台线程.

上代码


public class ThreadDemo8 {
    public static void main(String[] args) {
        Thread t=new Thread(()->{
            while(true){
            }
        });
        t.start();
       //此时默认是前台线程,阻止线程结束
    }
}


d3aaf7d684fd468fb0fb46a66d48b765.png

一直在跑,但是没有结束


public class ThreadDemo8 {
    public static void main(String[] args) {
        Thread t=new Thread(()->{
            while(true){
            }
        });
        t.setDaemon(true);//将值改为true,变为后台进程,不阻止线程结束
        t.start();
       //此时默认创建的线程是前台线程,阻止线程结束
    }
}


83c43164524b4fe4bfd742274543a7ec.png


t.isAlive()方法,结果是啥取决于线程的入口方法是否执行结束,如果执行执行结束,结果就为false,否则为true

说了这么多,来总结一下吧

1.前台线程会阻止Java进程 的结束,Java进程中所有的前台线程结束以后进程才能结束

2.后台进程不会阻止Java进程的结束,不管后台进程结没结束,只要所有前台进程结束,进程就结束

3.线程对应的入口方法执行完,这个时候线程就不存在了


最后:来区分一下t.start和t.run()方法:

作用功能不同:

  1. run方法的作用是描述线程具体要执行的任务;
  2. start方法的作用是真正的去申请系统线程


运行结果不同:

  1. run方法是一个类中的普通方法,主动调用和调用普通方法一样,会顺序执行一次;
  2. start调用方法后, start方法内部会调用Java 本地方法(封装了对系统底层的调用)真正的启动线程,并执行run方法中的代码,run 方法执行完成后线程进入销毁阶段。

今天的分享就到这里,下期再见


相关文章
|
3月前
|
消息中间件 程序员 调度
如何区分进程、线程和协程?看这篇就够了!
以下是内容摘要,已简化并保持在240字符以内: 嗨,我是小米!今天聊聊进程、线程和协程: - **进程**:资源分配基本单位,独立且隔离。 - **线程**:进程内执行单元,轻量级且共享资源。 - **协程**:比线程更轻量,适合I/O密集型任务。 每种都有独特特点和适用场景,选择合适可优化性能。希望对你有所帮助!更多内容,请关注我的公众号“软件求生”。
84 1
【多线程面试题十二】、阻塞线程的方式有哪些?
线程阻塞的方式包括调用sleep()方法、阻塞式IO操作、等待同步监视器的获取、等待通知(notify),以及慎用的suspend()方法。
|
5月前
|
安全 Java
一文搞懂线程!!
一文搞懂线程!!
38 6
一文搞懂线程!!
|
5月前
|
消息中间件 Java 调度
Java多线程基础-3:进程与线程间的区别的联系
进程是操作系统中运行的应用程序,具有独立内存空间,包含代码、数据和堆栈,是资源分配的最小单位,而线程是CPU调度的最小单位,是进程内的执行任务,多个线程可共享进程资源。
44 0
终于明白:有了线程,为什么还要有协程?
其实,在早期计算机并没有包含操作系统,这个时候,这个计算机只跑一个程序,这个程序独享计算机的所有资源,这个时候不存在什么并发问题,但是对计算机的资源来说,确实是一种浪费。早期编程都是基于单进程来进行,随着计算机技术的发展,于是,操作系统出现了,操作系统改变了这种现状,让计算机可以运行多个程序,并且不同的程序占用独立的计算机资源,如内存,CPU等。
|
Java 调度
多线程初阶——线程状态
多线程初阶——线程状态
79 0
如何处理JDK线程池内线程执行异常?讲得这么通俗,别还搞不懂
本篇 《如何处理 JDK 线程池内线程执行异常》 这篇文章适合哪些小伙伴阅读呢? 适合工作中使用线程池却不知异常的处理流程,以及不知如何正确处理抛出的异常
C++多线程 并行与并发 了解进程和线程 浅显的进行传参,调用
C++多线程 并行与并发 了解进程和线程 浅显的进行传参,调用
C++多线程 并行与并发 了解进程和线程 浅显的进行传参,调用