Java多线程总结(一) Java多线程概念及六大状态

进程和线程

进程和线程的概念

现在的电脑手机,都能宏观(现在的多核处理器能在真正意义上实现这样的并行处理;但是我们的进程数是不会受处理器核数的影响的,可以比处理器的核心数多,那时候还是要进行时间片的分配,也就是宏观的实现并行处理)的在同一个时刻多个事情(比如说,边写博客边听歌呀!)。这是因为有多进程,才能让我们这么方便的做这些事情。简单的说:一个应用程序就可以看作是一个进程(当然会有一个应用有多个进程的情况)。

而一个进程(可以直接想象成一个应用程序)能够同时执行多个任务是由多线程来进行实现的(举个栗子:一个音乐播放器可以同时进行听歌和下载歌曲)。

进程和线程的区别

本质的区别在于一个**进程拥有自己的一整套变量,而线程数据共享的**。

由于线程是共享变量的,因此线程之间的通信比进程之间的通信更有效、更容易

一般的操作系统中,线程比进程更加的轻量,创建、撤销一个线程比启动新进程的开销小得多

Java中多线程的实现

Java多线程实现的两种方式

通过自己写一个继承自Thread类的线程类。例如下面这样:

class MyThread extends Thread {

    private int num = 5;

    @Override
    public void run() {
        for (int i = 0; i < 10; i++) {
            if (num > 0) {
                System.out.println("ThreadId is:" + Thread.currentThread().getId() + ",num is " + num--);
            }
        }
    }
}

public class Test {

    public static void main(String[] args) {
        new MyThread().start();
        new MyThread().start();
    }
}

通过自己写一个实现了Runnable接口的Runnable类。例如下面这样:

class MyRunnable implements Runnable {

    private int num = 5;

    public void run() {
        for (int i = 0; i < 10; i++) {
            if (num > 0) {
                System.out.println("ThreadId is:" + Thread.currentThread().getId() + " ,num is " + num--);
            }
        }
    }
}

public class Test {

    public static void main(String[] args) {
        MyRunnable runnable = new MyRunnable();
        new Thread(runnable).start();
        new Thread(runnable).start();
    }
}

PS:不要调用Thread类或者Runnable对象的run方法。直接调用run方法,只会执行同一个线程中的任务,而不会启动新线程。

两种实现多线程方式的区别

通过实现Runnable接口的方式,可以让多个线程共享一个变量。而通过继承Thread类的方式不行。上面两个方式得到的结果如下:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-B0yn521j-1612354783645)(https://images-1254261164.cos.ap-chengdu.myqcloud.com/2018-11-08-164057.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-6lqpOBVU-1612354783647)(https://images-1254261164.cos.ap-chengdu.myqcloud.com/2018-11-08-164058.png)]

PS:通过继承Thread类的方式是不推荐的。因为我们应该将要并行运行的任务与运行机制解耦合。

线程的中断

线程中断的两种情况
  • 当线程的run方法执行方法体中最后一句后,并经由执行return语句返回时。
  • 出现了在方法体中没有捕获的异常时,线程将终止。PS:早期的Java版本中,有一个stop方法就是通过抛出ThreadDeath错误对象,由此杀死线程。但是这方法已经过时了,不要在代码中调用
线程中断的实现
  • 我们一般的线程中断是通过interrupt()和isInterrupted()两个方法结合来进行中断的。
  • 每个线程都有一个boolean变量用来标志一个线程是否被中断。interrupt()调用后此变量就为true。
  • 就像下面一样:
public class Test{
    public static void main(String[] args) throws InterruptedException {
        Runnable runnable = ()->{
            while (!Thread.currentThread().isInterrupted());
        };

        Thread thread = new Thread(runnable);
        thread.start();
        System.out.println(thread.isInterrupted());
        thread.interrupt();
        System.out.println(thread.isInterrupted());
    }
}

线程的六大状态

  • New(新创建)
    • 用new操作符创建一个新线程时,如new Thread®。此时线程处于New状态
  • Runnable(可运行)
    • 一旦调用start方法后,线程就处于Runnable状态(PS:一个可运行的线程可能正在运行也可能没有运行,这取决于操作系统给线程提供的运行时间)
  • Blocked(被阻塞)、Waiting(等待)和Timed waiting(计时等待)
    • 当一个线程试图获取一个内部的对象锁(不是java.util.concurrent库中的锁),而该锁被其他线程持有,则该线程处于Block状态
    • 当线程等待另一个线程通知调度器一个条件时,它自己进入Waiting状态
    • 当Thread.sleep、Object.wait、Thread.join、Lock.tryLock以及Condition.await的计时版方法被调用时,线程处于Timed waiting状态
  • Terminated(被终止)
    • 因为run方法正常退出而自然死亡。
    • 因为一个没有捕获的异常终止run方法而意外死亡。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-tplOpxhm-1612354783648)(https://images-1254261164.cos.ap-chengdu.myqcloud.com/2018-11-08-164100.png)]

线程的属性

线程优先级
  • 在默认的情况下,一个线程继承它的父类的优先级
  • 线程的优先级可以是MIN_PRIORITY(Thread类中定义为1)**与**MAX_PRIORITY(定义为10)之间的任意值。其中还有一个NORM_PRIORITY(在Thread类中定义为5)常量。
  • 但是,线程的优先级是高度依赖于系统的。当虚拟机依赖于宿主机平台的线程实现机制,Java线程的优先级映射到宿主机平台的优先级上,优先级的个数可能变多也可能变少。

守护线程

  • 线程对象通过调用setDaemon(true)方法将其设置为守护线程。
  • 守护线程的作用是为其它的线程提供服务。当程序中只有守护线程的时候,虚拟机就会退出
  • 由于守护线程的这个特点,因此守护线程应该永远不要去访问固有资源,如文件、数据库。

参考

  • Java核心技术 卷一

总结

  • 上面是对线程基本知识的介绍,也没啥好总结的。后面的内容继续介绍线程更深的东西。敬请期待~
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Dylan、

耕码不易,白嫖可耻

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值