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

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

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

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

线程

定义

线程(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 秒钟后销毁这个进程。

目录
相关文章
|
8天前
|
并行计算 数据处理 调度
Python中的并发编程:探索多线程与多进程的奥秘####
本文深入探讨了Python中并发编程的两种主要方式——多线程与多进程,通过对比分析它们的工作原理、适用场景及性能差异,揭示了在不同应用需求下如何合理选择并发模型。文章首先简述了并发编程的基本概念,随后详细阐述了Python中多线程与多进程的实现机制,包括GIL(全局解释器锁)对多线程的影响以及多进程的独立内存空间特性。最后,通过实例演示了如何在Python项目中有效利用多线程和多进程提升程序性能。 ####
|
10天前
|
Java
JAVA多线程通信:为何wait()与notify()如此重要?
在Java多线程编程中,`wait()` 和 `notify()/notifyAll()` 方法是实现线程间通信的核心机制。它们通过基于锁的方式,使线程在条件不满足时进入休眠状态,并在条件满足时被唤醒,从而确保数据一致性和同步。相比其他通信方式,如忙等待,这些方法更高效灵活。 示例代码展示了如何在生产者-消费者模型中使用这些方法实现线程间的协调和同步。
24 3
|
13天前
|
Linux 调度 C语言
深入理解操作系统:进程和线程的管理
【10月更文挑战第32天】本文旨在通过浅显易懂的语言和实际代码示例,带领读者探索操作系统中进程与线程的奥秘。我们将从基础知识出发,逐步深入到它们在操作系统中的实现和管理机制,最终通过实践加深对这一核心概念的理解。无论你是编程新手还是希望复习相关知识的资深开发者,这篇文章都将为你提供有价值的见解。
|
10天前
|
Java
java小知识—进程和线程
进程 进程是程序的一次执行过程,是系统运行的基本单位,因此进程是动态的。系统运行一个程序即是一个进程从创建,运行到消亡的过程。简单来说,一个进程就是一个执行中的程序,它在计算机中一个指令接着一个指令地执行着,同时,每个进程还占有某些系统资源如CPU时间,内存空间,文件,文件,输入输出设备的使用权等等。换句话说,当程序在执行时,将会被操作系统载入内存中。 线程 线程,与进程相似,但线程是一个比进程更小的执行单位。一个进程在其执行的过程中产生多个线程。与进程不同的是同类的多个线程共享同一块内存空间和一组系统资源,所以系统在产生一个线程,或是在各个线程之间做切换工作时,负担要比
21 1
|
15天前
|
存储 Unix Linux
进程间通信方式-----管道通信
【10月更文挑战第29天】管道通信是一种重要的进程间通信机制,它为进程间的数据传输和同步提供了一种简单有效的方法。通过合理地使用管道通信,可以实现不同进程之间的协作,提高系统的整体性能和效率。
|
15天前
|
消息中间件 存储 供应链
进程间通信方式-----消息队列通信
【10月更文挑战第29天】消息队列通信是一种强大而灵活的进程间通信机制,它通过异步通信、解耦和缓冲等特性,为分布式系统和多进程应用提供了高效的通信方式。在实际应用中,需要根据具体的需求和场景,合理地选择和使用消息队列,以充分发挥其优势,同时注意其可能带来的复杂性和性能开销等问题。
|
15天前
深入理解操作系统:进程与线程的管理
【10月更文挑战第30天】操作系统是计算机系统的核心,它负责管理计算机硬件资源,为应用程序提供基础服务。本文将深入探讨操作系统中进程和线程的概念、区别以及它们在资源管理中的作用。通过本文的学习,读者将能够更好地理解操作系统的工作原理,并掌握进程和线程的管理技巧。
31 2
|
16天前
|
调度 Python
深入浅出操作系统:进程与线程的奥秘
【10月更文挑战第28天】在数字世界的幕后,操作系统悄无声息地扮演着关键角色。本文将拨开迷雾,深入探讨操作系统中的两个基本概念——进程和线程。我们将通过生动的比喻和直观的解释,揭示它们之间的差异与联系,并展示如何在实际应用中灵活运用这些知识。准备好了吗?让我们开始这段揭秘之旅!
|
20天前
|
Java 调度
Java 线程同步的四种方式,最全详解,建议收藏!
本文详细解析了Java线程同步的四种方式:synchronized关键字、ReentrantLock、原子变量和ThreadLocal,通过实例代码和对比分析,帮助你深入理解线程同步机制。关注【mikechen的互联网架构】,10年+BAT架构经验倾囊相授。
Java 线程同步的四种方式,最全详解,建议收藏!
|
21天前
|
Linux 调度
探索操作系统核心:进程与线程管理
【10月更文挑战第24天】在数字世界的心脏,操作系统扮演着至关重要的角色。它不仅是计算机硬件与软件之间的桥梁,更是管理和调度资源的大管家。本文将深入探讨操作系统的两大基石——进程与线程,揭示它们如何协同工作以确保系统运行得井井有条。通过深入浅出的解释和直观的代码示例,我们将一起解锁操作系统的管理奥秘,理解其对计算任务高效执行的影响。

热门文章

最新文章

相关实验场景

更多