什么是线程和进程?是如何创建、同步、通信、销毁的?

简介: 什么是线程和进程?是如何创建、同步、通信、销毁的?

计算机系统中,线程和进程是两个基本的概念。多线程编程已经成为现代编程中比较常见的技术,因此对于线程和进程的深刻理解变得尤为重要。

本文将详细介绍线程和进程,包括定义、创建、同步、通信、销毁等方面的内容,并通过实例帮助读者更好地了解这两个概念。

线程

定义

线程(Thread)是指在单个程序中同时执行的一段指令流或执行流程。一个进程可以包含多个线程,每个线程可以执行不同的任务。

在 Java 中,线程是虚拟机中的一种轻量级对象,每个线程拥有自己的执行堆栈和程序计数器(Program Counter,PC),可以独立执行任务。

创建线程

Java 中创建线程有两种方式:

继承 Thread 类并重写 run 方法

public class MyThread extends Thread {
   
    public void run() {
   
        System.out.println("MyThread running");
    }
}

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

上面的代码创建了一个新的线程对象 myThread,并启动这个线程。在 MyThread 类中重写 run 方法是为了定义这个线程的执行逻辑。

实现 Runnable 接口并通过 Thread 类创建线程

public class MyRunnable implements Runnable {
   
    public void run() {
   
        System.out.println("MyRunnable running");
    }
}

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

上面的代码创建了一个实现 Runnable 接口的类 MyRunnable,并通过这个类创建了一个线程对象 myThread。在 MyRunnable 类中实现 run 方法是为了定义这个线程的执行逻辑。

线程同步

线程同步是指在多个线程之间协调执行的机制。当多个线程同时访问共享资源时,可能会出现数据不一致的情况。为了避免这种情况,需要使用同步机制来保证数据的一致性。

互斥锁

互斥锁(Mutex)是最常用的一种同步机制。互斥锁可以保证在任何时刻只有一个线程能够进入临界区(Critical Section),从而避免多个线程同时访问共享资源的问题。

在 Java 中,可以使用 synchronized 关键字来实现互斥锁。synchronized 关键字可以应用于方法或者某个代码块,以确保在同一时间只有一个线程可以访问这个方法或者代码块中的内容。

public class Counter {
   
    private int count;

    public synchronized void increment() {
   
        count++;
    }

    public synchronized int getCount() {
   
        return count;
    }
}

上面的代码定义了一个类 Counter,其中的 incrementgetCount 方法都使用了 synchronized 关键字。这样可以保证在任何时刻只有一个线程能够同时访问这两个方法,从而避免发生数据不一致的情况。

条件变量

条件变量是一种同步机制,可以用于多个线程之间的通信。条件变量通常结合互斥锁一起使用,在等待条件时会释放互斥锁,以便其他线程也可以获取到互斥锁。

在 Java 中,可以使用 waitnotify 方法来实现条件变量。wait 方法可以使当前线程进入等待状态,直到其他线程调用 notify 或者 notifyAll 方法来唤醒这个线程。notify 方法可以随机唤醒一个正在等待的线程,而 notifyAll 方法可以唤醒所有正在等待的线程。

public class MessageQueue {
   
    private List<String> queue = new ArrayList<>();

    public synchronized void put(String message) {
   
        queue.add(message);
        notify();
    }

    public synchronized String take() throws InterruptedException {
   
        while (queue.isEmpty()) {
   
            wait();
        }
        return queue.remove(0);
    }
}

上面的代码定义了一个类 MessageQueue,其中的 put 方法和 take 方法分别用于向队列中添加消息和取出消息。在 take 方法中,如果队列中没有消息,则会进入等待状态,并通过 wait 方法释放互斥锁。在 put 方法中,如果队列中有新的消息,则会通知正在等待的线程从等待状态中唤醒。

线程通信

线程通信是指在多个线程之间传递信息或者数据的机制。线程通信可以通过共享内存或者消息传递来实现。

共享内存

共享内存是一种线程通信的方式,可以让多个线程访问同一块内存区域。在使用共享内存时,需要使用互斥锁来保证数据的一致性。

public class Counter {
   
    private int count;

    public synchronized void increment() {
   
        count++;
        notifyAll();
    }

    public synchronized int getCount() throws InterruptedException {
   
        while (count == 0) {
   
            wait();
        }
        int result = count;
        count = 0;
        return result;
    }
}

上面的代码定义了一个类 Counter,其中的 increment 方法用于增加计数器的值,而 getCount 方法用于获取计数器当前的值,并将计数器清零。在 getCount 方法中,如果计数器的值为零,则会进入等待状态,等待其他线程调用 increment 方法来唤醒这个线程。

消息传递

消息传递是一种线程通信的方式,可以让多个线程之间通过消息来进行通信。消息传递有两种方式:共享队列和直接通信。

共享队列

共享队列是一种消息传递的方式,多个线程可以通过一个公共的队列来发送和接收消息。在使用共享队列时,需要使用互斥锁和条件变量来保证数据的一致性。

public class MessageQueue {
   
    private List<String> queue = new ArrayList<>();

    public synchronized void put(String message) {
   
        queue.add(message);
        notify();
    }

    public synchronized String take() throws InterruptedException {
   
        while (queue.isEmpty()) {
   
            wait();
        }
        return queue.remove(0);
    }
}

上面的代码定义了一个类 MessageQueue,其中的 put 方法和 take 方法分别用于向队列中添加消息和取出消息。在 take 方法中,如果队列中没有消息,则会进入等待状态,并通过 wait 方法释放互斥锁。在 put 方法中,如果队列中有新的消息,则会通知正在等待的线程从等待状态中唤醒。

直接通信

直接通信是一种消息传递的方式,多个线程之间通过直接发送消息来进行通信。在使用直接通信时,常用的方式有管道、套接字和消息队列等。

以管道为例,可以使用 PipedInputStreamPipedOutputStream 来实现两个线程之间的通信。

public class PipeDemo {
   
    public static void main(String[] args) throws Exception {
   
        PipedOutputStream output = new PipedOutputStream();
        PipedInputStream input = new PipedInputStream(output);

        Thread t1 = new Thread(() -> {
   
            try {
   
                output.write("Hello World".getBytes());
            } catch (IOException e) {
   
                e.printStackTrace();
            }
        });

        Thread t2 = new Thread(() -> {
   
            try {
   
                byte[] buffer = new byte[1024];
                int len = input.read(buffer);
                System.out.println(new String(buffer, 0, len));
            } catch (IOException e) {
   
                e.printStackTrace();
            }
        });

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

上面的代码定义了一个类 PipeDemo,该类通过 PipedOutputStreamPipedInputStream 实现了两个线程之间的通信。在 t1 线程中,向管道中写入了一条消息 "Hello World";在 t2 线程中,从管道中读取了该消息,并输出到控制台。

销毁线程

线程可以通过调用 interrupt 方法来中断执行,也可以通过设置 volatile 类型的标志位来通知线程退出。当线程不再需要时,可以使用 join 方法等待线程执行完毕并回收资源。

public class StopThreadDemo {
   
    private static volatile boolean stop = false;

    public static void main(String[] args) throws InterruptedException {
   
        Thread t = new Thread(() -> {
   
            while (!stop) {
   
                // do something
            }
        });
        t.start();
        Thread.sleep(1000);
        stop = true;
        t.join();
    }
}

上面的代码定义了一个类 StopThreadDemo,该类使用 volatile 类型的标志位来通知线程退出。

进程

定义

进程(Process)是计算机中的一个程序关于某个数据集合上的一次运行活动。一个进程可以包含多个线程,每个线程可以执行不同的任务。

在 Java 中,一个进程通常由多个线程组成,可以使用 java.lang.ProcessBuilder 类来创建和控制进程。

创建进程

Java 中可以使用 java.lang.ProcessBuilder 类来创建和控制进程。

public class ProcessDemo {
   
    public static void main(String[] args) throws Exception {
   
        ProcessBuilder builder = new ProcessBuilder("ls", "-lah");
        Process process = builder.start();

        InputStream inputStream = process.getInputStream();
        BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream));
        String line;
        while ((line = reader.readLine()) != null) {
   
            System.out.println(line);
        }

        int exitCode = process.waitFor();
        System.out.println("Exit code: " + exitCode);
    }
}

上面的代码创建了一个进程,并执行了 ls -lah 命令。通过读取进程的输入流,可以获取命令执行后的输出结果。调用 waitFor 方法可以等待进程执行完毕并获取进程的退出码。

进程同步

进程同步是指在多个进程之间协调执行的机制。当多个进程同时访问共享资源时,可能会出现数据不一致的情况。为了避免这种情况,需要使用同步机制来保证数据的一致性。

在 Java 中,可以使用管道、共享内存等方式来实现进程同步。以管道为例,可以使用 PipedInputStreamPipedOutputStream 来实现两个进程之间的通信。

进程通信

进程通信是指在多个进程之间传递信息或者数据的机制。进程通信可以通过共享内存或者消息传递来实现。

以管道为例,可以使用 PipedInputStreamPipedOutputStream 来实现两个进程之间的通信。

public class PipeDemo {
   
    public static void main(String[] args) throws Exception {
   
        Process p1 = new ProcessBuilder("echo", "Hello World").start();
        Process p2 = new ProcessBuilder("tr", "a-z", "A-Z").start();

        PipedOutputStream output = new PipedOutputStream(p1.getOutputStream());
        PipedInputStream input = new PipedInputStream(p2.getInputStream());
        p1.getOutputStream().close();
        p2.getInputStream().close();

        byte[] buffer = new byte[1024];
        int len;
        while ((len = input.read(buffer)) != -1) {
   
            output.write(buffer, 0, len);
        }
        output.close();

        int exitCode = p1.waitFor();
        System.out.println("Exit code: " + exitCode);
        exitCode = p2.waitFor();
        System.out.println("Exit code: " + exitCode);
    }
}

上面的代码创建了两个进程 p1p2,在 p1 进程中执行了 echo "Hello World" 命令,在 p2 进程中执行了 tr a-z A-Z 命令。通过管道将 p1 进程的输出和 p2 进程的输入连接起来,从而实现两个进程之间的通信。

销毁进程

进程可以通过调用 destroy 方法来销毁进程。当进程不再需要时,可以调用这个方法来释放所有相关资源。

public class StopProcessDemo {
   
    public static void main(String[] args) throws Exception {
   
        ProcessBuilder builder = new ProcessBuilder("ping", "-t", "localhost");
        Process process = builder.start();
        Thread.sleep(10000);
        process.destroy();
    }
}

上面的代码创建了一个进程,并在 10 秒钟后销毁这个进程。

目录
相关文章
|
22天前
|
调度 开发者 Python
深入浅出操作系统:进程与线程的奥秘
在数字世界的底层,操作系统扮演着不可或缺的角色。它如同一位高效的管家,协调和控制着计算机硬件与软件资源。本文将拨开迷雾,深入探索操作系统中两个核心概念——进程与线程。我们将从它们的诞生谈起,逐步剖析它们的本质、区别以及如何影响我们日常使用的应用程序性能。通过简单的比喻,我们将理解这些看似抽象的概念,并学会如何在编程实践中高效利用进程与线程。准备好跟随我一起,揭开操作系统的神秘面纱,让我们的代码运行得更加流畅吧!
|
22天前
|
消息中间件 Unix Linux
【C语言】进程和线程详解
在现代操作系统中,进程和线程是实现并发执行的两种主要方式。理解它们的区别和各自的应用场景对于编写高效的并发程序至关重要。
47 6
|
23天前
|
调度 开发者
深入理解:进程与线程的本质差异
在操作系统和计算机编程领域,进程和线程是两个核心概念。它们在程序执行和资源管理中扮演着至关重要的角色。本文将深入探讨进程与线程的区别,并分析它们在现代软件开发中的应用和重要性。
48 5
|
20天前
|
算法 调度 开发者
深入理解操作系统:进程与线程的管理
在数字世界的复杂编织中,操作系统如同一位精明的指挥家,协调着每一个音符的奏响。本篇文章将带领读者穿越操作系统的幕后,探索进程与线程管理的奥秘。从进程的诞生到线程的舞蹈,我们将一起见证这场微观世界的华丽变奏。通过深入浅出的解释和生动的比喻,本文旨在揭示操作系统如何高效地处理多任务,确保系统的稳定性和效率。让我们一起跟随代码的步伐,走进操作系统的内心世界。
|
23天前
|
调度 开发者
核心概念解析:进程与线程的对比分析
在操作系统和计算机编程领域,进程和线程是两个基本而核心的概念。它们是程序执行和资源管理的基础,但它们之间存在显著的差异。本文将深入探讨进程与线程的区别,并分析它们在现代软件开发中的应用和重要性。
41 4
|
1月前
|
并行计算 数据处理 调度
Python中的并发编程:探索多线程与多进程的奥秘####
本文深入探讨了Python中并发编程的两种主要方式——多线程与多进程,通过对比分析它们的工作原理、适用场景及性能差异,揭示了在不同应用需求下如何合理选择并发模型。文章首先简述了并发编程的基本概念,随后详细阐述了Python中多线程与多进程的实现机制,包括GIL(全局解释器锁)对多线程的影响以及多进程的独立内存空间特性。最后,通过实例演示了如何在Python项目中有效利用多线程和多进程提升程序性能。 ####
|
1月前
|
监控 JavaScript 前端开发
python中的线程和进程(一文带你了解)
欢迎来到瑞雨溪的博客,这里是一位热爱JavaScript和Vue的大一学生分享技术心得的地方。如果你从我的文章中有所收获,欢迎关注我,我将持续更新更多优质内容,你的支持是我前进的动力!🎉🎉🎉
24 0
|
5月前
|
运维 关系型数据库 MySQL
掌握taskset:优化你的Linux进程,提升系统性能
在多核处理器成为现代计算标准的今天,运维人员和性能调优人员面临着如何有效利用这些处理能力的挑战。优化进程运行的位置不仅可以提高性能,还能更好地管理和分配系统资源。 其中,taskset命令是一个强大的工具,它允许管理员将进程绑定到特定的CPU核心,减少上下文切换的开销,从而提升整体效率。
掌握taskset:优化你的Linux进程,提升系统性能
|
5月前
|
弹性计算 Linux 区块链
Linux系统CPU异常占用(minerd 、tplink等挖矿进程)
Linux系统CPU异常占用(minerd 、tplink等挖矿进程)
192 4
Linux系统CPU异常占用(minerd 、tplink等挖矿进程)
|
4月前
|
算法 Linux 调度
探索进程调度:Linux内核中的完全公平调度器
【8月更文挑战第2天】在操作系统的心脏——内核中,进程调度算法扮演着至关重要的角色。本文将深入探讨Linux内核中的完全公平调度器(Completely Fair Scheduler, CFS),一个旨在提供公平时间分配给所有进程的调度器。我们将通过代码示例,理解CFS如何管理运行队列、选择下一个运行进程以及如何对实时负载进行响应。文章将揭示CFS的设计哲学,并展示其如何在现代多任务计算环境中实现高效的资源分配。