美文网首页并发编程
并发编程(一):线程的基本应用

并发编程(一):线程的基本应用

作者: codeMover | 来源:发表于2020-03-30 22:18 被阅读0次

进程和线程

进程

  • 程序由指令和数据组成,但这些指令要运行,数据要读写,就必须将指令加载至CPU,数据加载至内存。在指令运行过程中需要用到磁盘、网络等设备。进程就是用来加载指令、管理内存、管理IO的。
  • 当一个程序被运行,从磁盘加载这个程序的代码至内存,这时就开启了一个进程。
  • 进程可以看做程序的一个实例。大部分程序可以同时运行多个实例(例如浏览器),有得只能启动一个实例进程(例如网易云音乐)。

线程

  • 一个进程之内可以分为一到多个线程。
  • 一个线程就是一个指令流,将指令流中的一条条指令以一定的顺序交给CPU执行。
  • Java中,线程作为最小的调度单位进程作为资源最小的分配单位

进程和线程对比

  • 进程基本上是相互独立的,而线程存在于进程内,是进程的一个子集
  • 进程拥有共享的资源,如内存空间等,供其内部线程共享
  • 进程间通信较为复杂(同一台计算机进程通信称为IPC,不同计算机之间需要通过网络,遵守共同协议,如HTTP协议)
  • 线程通信较为简单,同一进程内的线程共享内存,例如多线程访问共享资源
  • 线程更轻量,线程上下文切换成本一般要比进程上下文切换成本低

并行和并发

并发

  • 单核CPU,线程还是串行执行的。操作系统中有一个叫任务调度器的组件,将cpu时间片分给不同的线程使用,由于cpu在线程间的切换非常快,我们感觉是同时运行的。
  • 微观串行,宏观并行
  • 一般将线程轮流使用CPU的做法称为并发(concurrent)

并行

  • 多核CPU下,每个核都可以调度运行线程,这时候线程可以是并行的

并发和并行比较

  • 并发(concurrent)同一时间应对(dealing with)多件事情的能力
  • 并行(parallel)同一时间动手做(doing)多件事情的能力

创建和运行线程

方法一:继承Thread类

@Slf4j(topic = "ants.extendThread")
public class ExtendThread extends Thread{
    @Override
    public void run() {
        log.debug("创建线程一:继承Thread类,重写run方法");
    }

    public static void main(String[] args) {
        ExtendThread extendThread = new ExtendThread();
        extendThread.setName("t1");
        extendThread.start();
    }
}

方法二:实现Runnable接口

@Slf4j(topic = "ants.implRunnable")
public class ImplRunnable implements Runnable {
    @Override
    public void run() {
        log.debug("实现Runnable接口,重写run(),创建线程");
    }

    public static void main(String[] args) {
        Thread thread = new Thread(new ImplRunnable());
        thread.setName("t1");
        thread.start();
    }
}

继承Thread类和实现Runnable接口创建线程比较

  • 使用实现RUnnable接口的方式创建线程,分离了任务和线程之前的关系,代码更灵活
  • 使用Runnable接口方式,更容易和线程池高级API结合

方法三:实现Callable接口

@Slf4j(topic = "ants.ImplCallable")
public class ImplCallable implements Callable<Integer> {
    @Override
    public Integer call() throws Exception {
        log.debug("run-----");
        Thread.sleep(1000);
        return 10;
    }

    public static void main(String[] args) throws ExecutionException, InterruptedException {
        FutureTask<Integer> task = new FutureTask(new ImplCallable());
        Thread t = new Thread(task);
        t.start();
        Integer o = task.get();
        log.debug("result value:{}",o);
    }
}

查看进程方法

windows

  • tasklist:查看进程
  • taskkill:杀死进程 taskkill /F /PID 进程号

Linux

  • ps -ef|grep java
  • top top -H -p 进程号 H:查看线程 -p:进程id 在top中查看进程id中所有线程信息

Java

  • jps 插卡所有Java进程
  • jstack pid 查看某个Java进程的所有线程状态
  • jconsole 查看某个Java进程中线程的运行情况

线程运行原理

栈帧图解

栈帧图解.png

线程上下文切换

  • 线程CPU时间片用完
  • 垃圾回收
  • 更高优先级线程执行
  • 自己调用sleep、yield、synchronized等方法
    上下文切换由程序计数器(Java方法)保存当前线程下一条执行的执行指令地址
    上下文切换需要保存栈帧里面信息(局部变量表、返回地址、操作数栈等)

相关文章

网友评论

    本文标题:并发编程(一):线程的基本应用

    本文链接:https://www.haomeiwen.com/subject/vyibuhtx.html