• 浅谈对多线程的理解(一)


    今天我们先来聊聊有关线程的话题......

     

    一. 线程概述

    1. 简单区分程序、进程和线程

    程序是指一段静态的代码

    进程是指正在执行的程序,将静态的代码运行起来

    线程是指正在执行程序的小单元

    举个栗子,班级准备大扫除,在大扫除之前,老师在纸上列了一个清单,每个同学都有不同的工作任务,分配好任务之后,每个同学都是有条不紊地完成自己的任务,扫地的同学去扫地,擦黑板的同学去擦黑板,清理桌子的同学清理桌子......在这个例子里,这个清单就是程序,而这个班级的全体同学是一个整体,也就是一个进程,最后,这个班级里面一个个同学就是一个个线程。


    2. 理解进程

    理解线程之前,先简单理解一下进程。进程的三大特征:独立性、动态性、并发性。

    独立性:指进程是系统中独立存在的实体,拥有独立的资源(eg:私有的地址空间)。

    动态性:这是相对于程序而言的,程序是一段静态的代码,而进程是活动的,拥有自己的生命周期。

    并发性:多个进程可以在单个处理器上并发执行,互不影响。

    还是上面那栗子,这个班级就是一个进程,他是一个整体,他拥有自己的教室,有自己的班级名字,这里可以体现出独立性。这个班级的全体人员按照的任务清单干活,直至把教室打扫干净(即完成任务),这里可以体现出动态性。并发性呢,首先这个班级不只有一个,还有好多其他的班级,他们也可以打扫他们自己的教室,互不影响。


    3. 理解线程

    线程是进程的执行单元,在程序中,线程是独立的、并发的执行流。

    线程的特点:

    1. 每个线程有自己的堆栈,自己程序计数器,自己的局部变量,这里体现了线程的独立性。

    2. 相同父进程下的所有线程共享进程独立的内存单元(eg:代码段、进程的共有数据),为此可以实现线程间的相互通信。

    3. 多个线程之间也可以并发执行,互不影响。


    4. 多线程 VS 多进程

    1. 线程之间可以共享内存,而进程之间不可以。

    2. 系统创建线程代价比较小,而且多线程是实现多任务并发比多进程的效率更高。

    3. Java语言内置了多线程功能,简化了Java多线程编程。


    二. 线程的创建和启动

    1. 继承Thread类创建线程类

    步骤:

    1. 定义一个线程类,需继承Thread类。

    2. 重写父类的run( )方法,此方法是线程执行体,供cpu自动调用(cpu会用调度策略去处理就绪状态的线程)。

    3. 创建线程类的实例对象,调用start( )方法,这个方法告诉cpu这个线程对象进入就绪状态。

     1 package com.hx.thread;
     2  3 // 1.定义一个线程类,需继承Thread类。
     4 public class MyThread1 extends Thread {
     5     // 2.重写run方法
     6     public void run() {
     7         for (int i = 0; i < 100; i++) {
     8             System.out.println(Thread.currentThread().getName() + " " + i);
     9             try {
    10                 Thread.sleep(10);
    11             } catch (Exception e) {
    12                 e.printStackTrace();
    13             }
    14         }
    15     }
    16     
    17     public static void main(String[] args) throws Exception {
    18         // 3.创建线程实例,调用start方法,进入就绪状态,交给cpu
    19         MyThread1 myThread1 = new MyThread1();
    20         myThread1.start();
    21         for (int i = 0; i < 100; i++) {
    22             System.out.println(Thread.currentThread().getName() + "     " + i);
    23             Thread.sleep(10);
    24         }
    25     }
    26 }

    2. 实现Runnable接口创建线程类

    步骤:

    1. 定义一个线程类,需实现Runnable接口。

    2. 实现接口的run( )方法,此方法是线程执行体,供cpu自动调用(cpu会用调度策略去处理就绪状态的线程)。

    3. 创建线程类的实例对象。可是Runnable没有start( )方法,因此需要第4步。

    4. 创建一个Thread对象(真正的线程对象),用来包装上面的那个实例对象,然后调用start( )方法。

     1 package com.hx.thread;
     2  3 // 1.定义一个线程类,需实现Runnable接口。
     4 public class MyThread2 implements Runnable {
     5     // 2.实现接口的run( )方法
     6     @Override
     7     public void run() {
     8         for (int i = 0; i < 100; i++) {
     9             System.out.println(Thread.currentThread().getName() + " " + i);
    10             try {
    11                 Thread.sleep(10);
    12             } catch (Exception e) {
    13                 e.printStackTrace();
    14             }
    15         }
    16     }
    17 18     public static void main(String[] args) throws Exception {
    19         // 3.创建线程类的实例对象
    20         MyThread2 myThread2 = new MyThread2();
    21         // 4.创建一个Thread对象(真正的线程对象),用来包装上面的那个实例对象,然后调用start( )方法。
    22         Thread t = new Thread(myThread2);
    23         t.start();
    24         for (int i = 0; i < 100; i++) {
    25             System.out.println(Thread.currentThread().getName() + "     " + i);
    26             Thread.sleep(10);
    27         }
    28     }
    29 }

    3. 实现Callable接口创建线程类

    步骤:

    1. 定义一个线程类,需实现Callable接口。

    1. 实现Callable接口的call( )方法,此方法是线程执行体。

    1. 创建线程类的实例对象。

    1. 创建FutureTask的对象来包装线程类实例对象。

    1. 创建Thread的对象来包装Future类的实例对象。

     1 package com.hx.thread;
     2 import java.util.concurrent.Callable;
     3 import java.util.concurrent.FutureTask;
     4  5 // 1.定义一个线程类,需实现Callable接口
     6 public class MyThread3 implements Callable {
     7     // 2.实现Callable接口的call()方法
     8     @Override
     9     public String call() throws Exception {
    10         for (int i = 0; i < 100; i++) {
    11             System.out.println(Thread.currentThread().getName() + " " + i);
    12             Thread.sleep(10);
    13         }
    14         return Thread.currentThread().getName();
    15     }
    16 17     public static void main(String[] args) throws Exception {
    18         // 3.创建线程类的实例对象
    19         MyThread3 myThread3 = new MyThread3();
    20         // 4.创建FutureTask的实例对象来包装线程类实例对象
    21         FutureTask futureTask = new FutureTask(myThread3);
    22         // 5.创建Thread的实例对象来包装Future类的实例对象
    23         Thread t = new Thread(futureTask);
    24         t.start();
    25         for (int i = 0; i < 100; i++) {
    26             System.out.println(Thread.currentThread().getName() + "     " + i);
    27             Thread.sleep(10);
    28         }
    29         // 打印出call()方法的返回值
    30         System.out.println(futureTask.get());
    31     }
    32 }

    4. 三种方式的对比

    1. 采用继承Thread类这种方式来创建线程,编写简单,可是由于Java不支持多继承,所以不能再继承其他父类。

    2. 采用实现Runnable接口或Callable接口,可以继承其他类,多个线程可以共享同一个target对象,非常适合多个线程来处理同一资源的情况,可以更好地体现面向对象的特点,不过编写比较复杂。

    3. 采用实现Callable接口,call( )方法是线程执行体,有返回值,可以抛出异常,其功能比run( )方法更强大。


    三. 线程的生命周期


    四. 控制线程

    Thread类的工具方法

    join( ):让一个线程等待另外一个线程完成的方法,当在某个程序执行流中调用其他线程的join方法,调用线程将被阻塞,直至join线程完成。

    setDaemon(true):指定线程设置为后台线程。在start( )之前调用。后台线程,又称守护线程、精灵线程,其作用是为其他线程提供服务(eg:JVM的垃圾回收线程),如果所有的前台线程都死亡,后台线程也会自动死亡。

    sleep( long time):设置线程睡眠时间,参数单位为毫秒,调用此方法线程进入阻塞状态。

    setPriority(int newPriority):设置优先级,参数范围:1-10,一般使用三个静态常量(MAX_PRIORITY、MIN_PRIORITY、NORM_PRIORITY)。


     

    嘻嘻,今天的内容就先到这吧,欢迎大家前来留言。

    由于现在个人水平有限,文章若存不当之处,还请各位大佬们加以斧正。

  • 相关阅读:
    MS面试归来:)
    准备出发到成都
    线程的同步机制(zz)
    Windows Vista(zz)
    这几天上海热晕了
    微软官方:Vista硬件要求指南(zz)
    有趣的递归缩写(Recursive acronym)
    《三国志》生僻人名读法集(zz)
    Git bash常用命令
    各大输入法分类词库内部格式的简单比较
  • 原文地址:https://www.cnblogs.com/q964024886/p/10763934.html
Copyright © 2020-2023  润新知