什么是并发模式?

并发性模式是一类专门用于处理并发编程问题的设计模式。由于并发编程具有复杂性高、容易出错等特点,因此需要一些可靠的模式来解决这些问题。并发性模式可以帮助开发人员更好地理解和设计并发编程的代码,提高并发编程的可维护性和可扩展性。

并发性模式包括但不限于以下几种:

  1. 读写锁模式:用于提高多线程读写操作的效率,减少锁的竞争。
  2. 生产者-消费者模式:用于解决生产者和消费者之间的数据传递问题,提高系统的并发性能。
  3. 线程池模式:用于管理线程的创建、销毁和复用,避免创建过多的线程带来的性能问题。
  4. 信号量模式:用于控制并发访问资源的数量,避免资源竞争问题。
  5. 互斥锁模式:用于解决多线程之间的同步问题,确保共享资源的互斥访问。
  6. 观察者模式:用于实现对象之间的松耦合,当一个对象的状态发生改变时,通知其他观察者对象进行相应的处理。

并发性模式是设计模式中的一个重要分支,对于实现高效的并发编程非常有帮助。但是并发性模式的正确使用需要开发人员具有一定的并发编程经验和技能。

高并发下使用这些就可以提高性能

  1. 读写锁模式:例如Java中的ReentrantReadWriteLock,用于提高多线程读写操作的效率,可以在读操作中共享锁,在写操作中排他锁,减少锁的竞争。
  2. 生产者-消费者模式:例如Java中的BlockingQueue,用于解决生产者和消费者之间的数据传递问题,提高系统的并发性能。生产者将数据放入队列,消费者从队列中取出数据进行处理。
  3. 线程池模式:例如Java中的ThreadPoolExecutor,用于管理线程的创建、销毁和复用,避免创建过多的线程带来的性能问题。通过线程池,可以限制线程的数量,提高线程的复用率,从而降低线程创建和销毁的开销。
  4. 信号量模式:例如Java中的Semaphore,用于控制并发访问资源的数量,避免资源竞争问题。通过信号量,可以控制对共享资源的并发访问数量,从而实现对资源的保护。
  5. 互斥锁模式:例如Java中的synchronized关键字或Lock接口,用于解决多线程之间的同步问题,确保共享资源的互斥访问。通过互斥锁,可以保证同一时刻只有一个线程能够访问共享资源。
  6. 观察者模式:例如Java中的java.util.Observer和java.util.Observable接口,用于实现对象之间的松耦合,当一个对象的状态发生改变时,通知其他观察者对象进行相应的处理。观察者模式中,被观察者对象维护了一个观察者对象列表,当被观察者对象状态发生改变时,遍历观察者列表,通知各个观察者对象进行处理。

信号量(Semaphore)是操作系统中一种用于进程间同步和互斥的机制。在并发编程中,信号量是一种用于控制对共享资源的访问的计数器。

信号量有两个主要操作:P(Produce,生产)和V(Value,值),也叫wait和signal。P操作减少信号量的值(如果不为零),而V操作增加信号量的值。

当一个线程需要访问共享资源时,它会先尝试进行P操作,如果信号量的值大于零,则减少信号量的值并允许线程访问共享资源。如果信号量的值为零,则线程需要等待,直到另一个线程进行V操作并增加信号量的值。

下面是一个简单的Java代码示例,使用信号量控制对共享资源的访问:

import java.util.concurrent.Semaphore;

public class SemaphoreExample {
    private static final int MAX_THREADS = 10;
    private static final Semaphore semaphore = new Semaphore(5);

    public static void main(String[] args) {
        for (int i = 0; i < MAX_THREADS; i++) {
            Thread thread = new Thread(new Worker(i));
            thread.start();
        }
    }

    static class Worker implements Runnable {
        private final int id;

        public Worker(int id) {
            this.id = id;
        }

        @Override
        public void run() {
            try {
                System.out.println("Worker " + id + " is waiting to acquire semaphore...");
                semaphore.acquire();
                System.out.println("Worker " + id + " has acquired semaphore.");
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            } finally {
                semaphore.release();
                System.out.println("Worker " + id + " has released semaphore.");
            }
        }
    }
}

在这个示例中,有10个线程需要访问共享资源,但是信号量的值被初始化为5,所以只有5个线程可以同时访问共享资源。其他5个线程需要等待,直到有一个线程释放信号量并允许其他线程访问共享资源。

在这段代码中, new Worker 实际上是创建一个 Worker 实例对象,并将其作为参数传递给 new Thread 的构造函数中。因为 Thread 构造函数的参数需要一个 Runnable 类型的对象,而 Worker 实现了 Runnable 接口,所以可以将 Worker 对象传递给 Thread 的构造函数中。

这种做法可以将工作线程(即 Worker)与执行线程(即 Thread)分离开来,这样在需要修改线程执行逻辑时,只需要修改 Worker 实现即可,而不必修改 Thread 的构造函数和其他的线程相关逻辑。这也是一种解耦的方式。

在Java中,线程的启动分为两个阶段:

  1. 将线程对象加入到线程调度器中,让系统分配CPU资源来执行线程;
  2. 执行线程对象的 run 方法。

在代码中,start 方法用于启动线程,将线程对象加入到线程调度器中。当系统分配到CPU资源时,会执行线程对象的 run 方法。

因此,start 方法的作用是启动线程,而 run 方法是线程的实际执行代码。如果直接调用 run 方法,那么线程并不会启动,而是相当于普通的方法调用,只有当前线程的主线程在执行。

在正常情况下,我们应该使用 start 方法来启动线程,而不是直接调用 run 方法。这样才能让系统对线程进行调度,分配资源并执行线程的代码。

线程调度器是操作系统内核的一部分,它负责决定哪些线程能够执行,并在多个线程之间进行切换,以实现多任务处理。线程调度器的主要作用是协调和管理多个线程的执行,以保证系统的效率和稳定性。

在操作系统中,每个线程都有一个优先级,线程调度器根据线程的优先级和调度策略,决定哪个线程可以获得 CPU 时间片,并在多个线程之间进行切换。调度策略包括时间片轮转、抢占式调度等。

在 Java 中,线程调度器是由 JVM(Java Virtual Machine)实现的,它负责决定哪些线程可以获得 CPU 时间片,并在多个线程之间进行切换。JVM 根据线程的优先级和调度策略来进行线程调度,但是具体的实现方式是由操作系统来决定的。

需要注意的是,由于线程的调度是由操作系统和 JVM 共同协作完成的,因此不同的操作系统和 JVM 实现可能会有所不同。在编写多线程程序时,需要考虑不同环境下的线程调度特性,以确保程序的正确性和可移植性。

读写锁模式是一种并发模式,它允许多个线程同时读取共享资源,但只允许一个线程写入共享资源。在读写锁模式中,读操作和写操作之间是互斥的,但读操作之间是非互斥的,这样可以在一定程度上提高并发性能。

读写锁模式包含两种锁:读锁和写锁。读锁可以被多个线程同时持有,只要没有线程持有写锁;写锁只能被一个线程持有,直到写操作完成后才会释放锁。读写锁模式可以用于高并发环境中,提高共享资源的读写性能,避免竞争条件和死锁等问题。

在 Java 中,读写锁模式被封装在 java.util.concurrent 包中的 ReentrantReadWriteLock 类中。这个类提供了两个锁:读锁和写锁,可以使用它们来实现读写锁模式。

使用读写锁模式的步骤如下:

  1. 创建一个 ReentrantReadWriteLock 对象;
  2. 从 ReentrantReadWriteLock 对象中获取读锁或写锁;
  3. 使用锁来保护共享资源的读写操作;
  4. 释放锁。

下面是一个简单的 Java 代码示例,演示如何使用读写锁模式:

import java.util.concurrent.locks.ReentrantReadWriteLock;

public class ReadWriteLockDemo {
    private ReentrantReadWriteLock lock = new ReentrantReadWriteLock();
    private int value;

    public int getValue() {
        lock.readLock().lock(); // 获取读锁
        try {
            return value;
        } finally {
            lock.readLock().unlock(); // 释放读锁
        }
    }

    public void setValue(int value) {
        lock.writeLock().lock(); // 获取写锁
        try {
            this.value = value;
        } finally {
            lock.writeLock().unlock(); // 释放写锁
        }
    }
}

生产者消费者是一种常见的并发模式,它涉及到两类线程:生产者和消费者。生产者负责生产数据并将其存储在共享缓冲区中,消费者从缓冲区中获取数据并进行处理。在这种模式中,生产者和消费者是独立的并发单元,通过共享缓冲区来通信。

生产者消费者模式主要有三个元素:

  1. 缓冲区:生产者将生产的数据放到缓冲区中,消费者从缓冲区中获取数据进行处理。
  2. 生产者:负责生产数据,并将其放到缓冲区中。
  3. 消费者:负责从缓冲区中获取数据并进行处理。

在生产者消费者模式中,通常使用队列来作为共享的缓冲区,队列可以是有界的或无界的。当队列为有界队列时,如果队列已满,则生产者必须等待,直到有空间可用;当队列为无界队列时,则不会出现生产者等待的情况。

生产者消费者模式还可以通过使用多个生产者和多个消费者来进行扩展,从而实现更高的并发性。

以下是一个简单的Java代码示例,演示了如何使用生产者消费者模式实现数据的生产和消费:

import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.BlockingQueue;

public class ProducerConsumerExample {
    public static void main(String[] args) {
        BlockingQueue<Integer> queue = new ArrayBlockingQueue<>(10);

        Thread producerThread = new Thread(() -> {
            try {
                int i = 0;
                while (true) {
                    queue.put(i);
                    System.out.println("Produced: " + i);
                    i++;
                    Thread.sleep(1000);
                }
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        });

        Thread consumerThread = new Thread(() -> {
            try {
                while (true) {
                    int value = queue.take();
                    System.out.println("Consumed: " + value);
                    Thread.sleep(5000);
                }
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        });

        producerThread.start();
        consumerThread.start();
    }
}

#你觉得今年春招回暖了吗#
全部评论
马了学习一下
点赞 回复 分享
发布于 2023-03-19 22:27 山东
感谢大佬分享
点赞 回复 分享
发布于 2023-03-19 22:15 四川

相关推荐

11-19 18:44
已编辑
成都理工大学 Java
程序员花海:我面试过100+校招生,大厂后端面试不看ACM,竞赛经历含金量低于你有几份大厂实习 这个简历整体来看不错 可以海投
如何写一份好简历
点赞 评论 收藏
分享
评论
点赞
收藏
分享

创作者周榜

更多
牛客网
牛客网在线编程
牛客网题解
牛客企业服务