前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >多线程笔记0406

多线程笔记0406

作者头像
Remember_Ray
发布2020-04-10 16:03:15
3190
发布2020-04-10 16:03:15
举报
文章被收录于专栏:Ray学习笔记Ray学习笔记

线程与进程

线程

一条线程指的是进程中一个单一顺序的控制流,一个进程中可以并发多个线程,每条线程并行执行不同的任务。多线程是多任务的一种特别形式,但多线程使用了更小的资源开销。

进程

一个进程包括有操作系统分配的内存空间,包含一个或多个线程。一个线程不能独立的存在。它必须是进程的一部分。一个进程一直运行直到所有的非守护线程都结束运行后才能结束。

进程

线程

定义

进程是处于运行中的程序,并且具有一定的独立功能。进程是系统进行资源分配和调度的一个单位。当程序进入内容时,即为进程。

线程是进程的组成部分,一个进程可以拥有多个线程,而一个线程必须拥有一个父进程。线程可以拥有自己的堆栈,自己的程序计数器和局部变量,但不能拥有系统资源。它与父进程的其他线程共享该进程的所有资源。

特点

1. 独立性:进程是系统中独立存在的实体,它可以独立拥有资源,每一个进程都有自己独立的地址空间,没有进程本身的运行,用户进程不可以直接访问其他进程的地址空间。2. 动态性:进程与程序的区别在于进程是动态的,进程中有时间的概念,进程具有自己的生命周期和各种不同的状态。3. 并发性:多个进程可以在单个处理器上并发执行,互不影响。

1. 线程可以完成一定任务,可以和其他线程共享父进程的共享变量和部分环境,互相协作来完成任务。2. 线程是独立运行的,其不知道进程中是否还有其他线程存在。3. 线程的执行时是抢占式,也就是说当前执行的线程随时可能被挂起,一边运行另一个线程。4. 一个线程可以创建或撤销另一个线程,一个进程中的多个线程可以并发执行。

生命周期

一个线程对象在它的生命周期内,需要经历五种状态:

  1. 新生状态(New):使用 new 关键字建立一个线程对象后,该线程对象就处于新生状态。处于新生状态的线程有自己的内存空间,通过调用 start() 方法进入就绪状态。
  2. 就绪状态(Runnable):处于就绪状态的线程已经具备了运行条件,但是还没有被分配到CPU,处于“线程就绪队列”,等待系统为其分配CPU。就绪状态并不是执行状态,当系统选定一个等待执行的Thread对象后,它就会进入执行状态。一旦获得CPU,线程就进入运行状态并自动调用自己的run方法。
  3. 运行状态(Running):在运行状态的线程执行自己run方法中的代码,直到调用其他方法而终止或等待某资源而阻塞或完成任务而死亡。如果在给定的时间片内没有执行结束,就会被系统给换下来回到就绪状态。也可能由于某些“导致阻塞的事件”而进入阻塞状态。
  4. 阻塞状态(Blocked):阻塞指的是暂停一个线程的执行以等待某个条件发送(如某资源就绪)。
  5. 死亡状态(Terminated):死亡状态是线程声明周期中的最后一个阶段,当一个线程进入死亡状态以后,就不能再回到其他状态了。

导致线程进入就绪状态的原因

  1. 新建线程:调用 start() 方法,进入就绪状态;
  2. 阻塞线程:阻塞解除,进入就绪状态;
  3. 运行线程:调用 yield() 方法,直接进入就绪状态;
  4. 运行线程:JVM将CPU资源从本线程切换到其他线程。

导致线程进入阻塞状态的原因

  1. 执行 sleep(int millsecond) 方法,使当前线程休眠,进入阻塞状态。当指定的时间到了后,线程进入就绪状态。
  2. 执行 wait() 方法,使当前线程进入阻塞状态。当使用 nofity() 方法唤醒这个线程后,它进入就绪状态。
  3. 线程运行时,某个操作进入阻塞状态,比如执行IO流操作( read() / write() 方法本身就是阻塞的方法)。只有当引起该操作阻塞的原因消失后,线程进入就绪状态。
  4. join() 线程联合:当某个线程等待另一个线程执行结束后,才能继续执行时(使用 join() 方法)。

导致线程进入死亡状态的原因

  1. 正常运行的线程完成了 run() 方法内的全部工作;
  2. 当程序发生异常,线程抛出一个未捕获的 Exception 或 Error;
  3. 线程被强制终止,如通过执行 stop() 或者 destroy() 方法来终止一个线程(该方法容易导致死锁,不推荐使用)。

Thread 简介

Thread 类实现了 Runnable 接口,在 Thread 类中,有一些比较关键的属性,比如:

  1. name 是表示 Thread 的名字,可以通过 Thread 类的构造器中的参数来指定线程名字;
  2. priority 表示线程的优先级(最大值为10,最小值为1,默认值为5);
  3. daemon 表示线程是否是守护线程;
  4. target 表示要执行的任务。

由于使用 Thread 需要继承该类,限制了程序的扩展,一般不推荐使用 Thread。

Runnable 简介

如果一个类继承 Thread,则不适合资源共享。但是如果实现了 Runnable 接口的话,则很容易的实现资源共享。

实现 Runnable 接口比继承 Thread 类具有以下优势:

  1. 可以避免 JAVA 中的单继承限制。
  2. 多个线程都是基于某一个Runnable对象建立的,它们会共享Runnable对象上的资源。
  3. 线程池只能放入实现 Runnable 或 callable 类线程,不能直接放入继承 Thread 的类。

一般推荐使用 Runnable。

Thread 和 Runnable 示例

下面通过示例更好的理解Thread和Runnable,借鉴网上一个比较具有说服性的例子:3个人一共卖10张门票。

Thread 示例

Java

代码语言:javascript
复制
class MyThread extends Thread {

    private int ticket = 10;
    private int count = 20;

    @Override
    public void run() {
        for (int i = 0; i < count; i++) {
            if (this.ticket > 0) {
                System.out.println(this.getName() + " 卖票:" + this.ticket--);
            }
        }
    }
}

启动线程

Java

代码语言:javascript
复制
public static void main(String[] args) {

    // 启动三个线程,t1,t2,t3,每个线程各卖10张票
    MyThread t1 = new MyThread();
    MyThread t2 = new MyThread();
    MyThread t3 = new MyThread();

    t1.start();
    t2.start();
    t3.start();
}

运行结果

Code

代码语言:javascript
复制
Thread-0 卖票:10
Thread-0 卖票:9
Thread-0 卖票:8
Thread-0 卖票:7
Thread-0 卖票:6
Thread-0 卖票:5
Thread-0 卖票:4
Thread-0 卖票:3
Thread-0 卖票:2
Thread-0 卖票:1
Thread-1 卖票:10
Thread-1 卖票:9
Thread-1 卖票:8
Thread-1 卖票:7
Thread-1 卖票:6
Thread-1 卖票:5
Thread-1 卖票:4
Thread-2 卖票:10
Thread-1 卖票:3
Thread-2 卖票:9
Thread-1 卖票:2
Thread-2 卖票:8
Thread-1 卖票:1
Thread-2 卖票:7
Thread-2 卖票:6
Thread-2 卖票:5
Thread-2 卖票:4
Thread-2 卖票:3
Thread-2 卖票:2
Thread-2 卖票:1

说明

主线程 main 创建并启动 3个 MyThread 子线程,每个子线程都各自卖出了10张门票。

Runnable 示例

Java

代码语言:javascript
复制
class MyRunnable implements Runnable {

    private int ticket = 10;
    private int count = 20;

    public void run() {
        for (int i = 0; i < count; i++) {
            if (this.ticket > 0) {
                System.out.println(Thread.currentThread().getName() + " 卖票:" + this.ticket--);
            }
        }
    }
}

启动线程

Java

代码语言:javascript
复制
public static void main(String[] args) {

    MyRunnable myRunnable = new MyRunnable();
    // 启动三个线程,t1,t2,t3(它们共用一个Runnable对象),这三个线程一共卖10张票
    Runnable target;
    Thread t1 = new Thread(myRunnable);
    Thread t2 = new Thread(myRunnable);
    Thread t3 = new Thread(myRunnable);

    t1.start();
    t2.start();
    t3.start();
}

运行结果

Code

代码语言:javascript
复制
Thread-0 卖票:10
Thread-0 卖票:9
Thread-0 卖票:8
Thread-0 卖票:7
Thread-0 卖票:6
Thread-1 卖票:5
Thread-0 卖票:4
Thread-0 卖票:2
Thread-0 卖票:1
Thread-1 卖票:3

---- 但会存在以下情况 ----
Thread-0 卖票:10
Thread-0 卖票:9
Thread-0 卖票:8
Thread-0 卖票:7
Thread-0 卖票:6
Thread-0 卖票:5
Thread-0 卖票:4
Thread-0 卖票:3
Thread-0 卖票:2
Thread-0 卖票:1
Thread-2 卖票:0
Thread-1 卖票:10

说明

主线程main创建并启动3个子线程,而且这3个子线程都是基于“myRunnable这个Runnable对象”而创建的。运行结果是这3个子线程一共卖出了10张票。这说明它们是共享了MyRunnable接口的。

本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2020-04-06|,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 线程与进程
    • 线程
      • 进程
      • 生命周期
        • 导致线程进入就绪状态的原因
          • 导致线程进入阻塞状态的原因
            • 导致线程进入死亡状态的原因
            • Thread 简介
            • Runnable 简介
            • Thread 和 Runnable 示例
              • Thread 示例
                • Runnable 示例
                领券
                问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档