高并发场景以及并发锁使用

一、高并发概述
高并发是指系统需要同时处理大量的请求或任务的能力,也就是系统的并发处理能力。在互联网应用中,高并发能够提高系统的吞吐量和资源利用率,是衡量系统性能的重要指标。
二、高并发的使用场景
互联网大型网站:如电商促销活动(双十一、黑五)、抢票系统、直播弹幕系统等,需要同时处理大量用户请求。
金融交易系统:如股票交易、在线支付,需要在短时间内处理大量交易请求,保证数据一致性。
即时通讯应用:如微信、QQ,需要实时处理大量消息的收发。
游戏服务器:在线游戏需要同时支持大量玩家的实时交互。
物联网应用:大量的设备同时向服务器发送数据,需要高并发的处理能力。
三、高并发的代码案例

  1. 使用 Java 的多线程处理高并发
    以下是一个简单的示例,使用线程池来处理高并发任务:
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class HighConcurrencyExample {
    public static void main(String[] args) {
        // 创建一个固定大小的线程池
        ExecutorService executorService = Executors.newFixedThreadPool(10);

        // 模拟高并发请求
        for (int i = 0; i < 1000; i++) {
            final int index = i;
            executorService.execute(() -> {
                processRequest(index);
            });
        }

        // 关闭线程池
        executorService.shutdown();
    }

    public static void processRequest(int index) {
        // 处理请求的逻辑
        System.out.println("处理请求:" + index);
    }
}

说明:
使用 ExecutorService 创建一个线程池,提高线程重用率,避免频繁创建和销毁线程的开销。
模拟了 1000 个并发请求,通过线程池来处理。
2. 使用 Netty 框架构建高并发服务器
Netty 是一款高性能的 Java NIO 网络框架,适用于开发高并发的网络应用程序。

package com.example;

import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.*;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;

public class NettyServer {
    public static void main(String[] args) throws Exception {
        // 创建 Boss 和 Worker 线程组
        EventLoopGroup bossGroup = new NioEventLoopGroup();
        EventLoopGroup workerGroup = new NioEventLoopGroup();

        try {
            // 创建服务器启动对象
            ServerBootstrap bootstrap = new ServerBootstrap();
            bootstrap.group(bossGroup, workerGroup)
                    .channel(NioServerSocketChannel.class) // 使用 NIO 通信方式
                    .childHandler(new ChannelInitializer<Channel>() { // 初始化通道
                        @Override
                        protected void initChannel(Channel ch) throws Exception {
                            // 添加自定义的处理器
                            ch.pipeline().addLast(new SimpleServerHandler());
                        }
                    });

            // 绑定端口,启动服务
            ChannelFuture future = bootstrap.bind(8080).sync();
            System.out.println("服务器启动在端口:8080");

            // 监听关闭事件
            future.channel().closeFuture().sync();
        } finally {
            // 优雅地关闭线程组
            bossGroup.shutdownGracefully();
            workerGroup.shutdownGracefully();
        }
    }

    // 自定义处理器
    static class SimpleServerHandler extends ChannelInboundHandlerAdapter {
        @Override
        public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
            ByteBuf inBuffer = (ByteBuf) msg;
            String received = inBuffer.toString(io.netty.util.CharsetUtil.UTF_8);

            System.out.println("服务器接收到消息:" + received);

            // 回复客户端
            String response = "处理成功";
            ByteBuf outBuffer = Unpooled.copiedBuffer(response, io.netty.util.CharsetUtil.UTF_8);
            ctx.writeAndFlush(outBuffer);
        }

        @Override
        public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
            cause.printStackTrace();
            ctx.close();
        }
    }
}

说明:
使用 Netty 构建了一个简单的服务器,可以处理大量并发的客户端连接和请求。
Netty 基于 NIO 的事件驱动机制,可以有效地提升高并发处理能力。
并发锁的使用场景和代码案例
一、并发锁的概述
在高并发场景下,为了保证共享资源的正确性,避免数据不一致等问题,需要对一些关键代码块进行同步控制,并发锁就是实现线程同步的一种机制。
二、并发锁的使用场景
共享资源的互斥访问:当多个线程需要读写同一个共享变量或数据结构时,需要使用锁来保证同一时刻只有一个线程访问。
保证数据一致性:在对数据进行修改、更新操作时,确保线程之间的数据一致性。
避免死锁和资源竞争:通过合理使用锁,避免线程因为资源竞争而陷入死锁。
三、并发锁的代码案例
1. 使用 synchronized 关键字

package com.example;

public class Counter {
    private int count = 0;

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

    public int getCount() {
        return count;
    }
}
package com.example;

public class SynchronizedExample {
    public static void main(String[] args) throws InterruptedException {
        Counter counter = new Counter();

        // 创建多个线程同时访问 increment 方法
        Thread t1 = new Thread(() -> runIncrement(counter));
        Thread t2 = new Thread(() -> runIncrement(counter));

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

        t1.join();
        t2.join();

        System.out.println("最终计数值:" + counter.getCount());
    }

    public static void runIncrement(Counter counter) {
        for (int i = 0; i < 10000; i++) {
            counter.increment();
        }
    }
}

说明:
increment() 方法被 synchronized 修饰,保证同一时刻只有一个线程能执行该方法,防止并发问题。
多个线程同时对 count 进行自增操作,如果不使用锁,可能导致计数结果不正确。
2. 使用 ReentrantLock

package com.example;

import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

public class LockExample {
    private int count = 0;

    private final Lock lock = new ReentrantLock();

    public void increment() {
        lock.lock(); // 获取锁
        try {
            count++;
        } finally {
            lock.unlock(); // 释放锁
        }
    }

    public int getCount() {
        return count;
    }
}
package com.example;

public class ReentrantLockExample {
    public static void main(String[] args) throws InterruptedException {
        LockExample counter = new LockExample();

        // 创建多个线程同时访问 increment 方法
        Thread t1 = new Thread(() -> runIncrement(counter));
        Thread t2 = new Thread(() -> runIncrement(counter));

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

        t1.join();
        t2.join();

        System.out.println("最终计数值:" + counter.getCount());
    }

    public static void runIncrement(LockExample counter) {
        for (int i = 0; i < 10000; i++) {
            counter.increment();
        }
    }
}

说明:
使用 ReentrantLock 来实现显式锁控制,功能类似于 synchronized,但提供了更灵活的功能。
需要手动获取和释放锁,必须在 finally 块中释放锁,避免因异常导致死锁。
3. 使用 ReadWriteLock

package com.example;

import java.util.concurrent.locks.ReadWriteLock;
import java.util.concurrent.locks.ReentrantReadWriteLock;

public class ReadWriteLockExample {
    private int value = 0;

    private final ReadWriteLock rwLock = new ReentrantReadWriteLock();

    public void increment() {
        rwLock.writeLock().lock();
        try {
            value++;
        } finally {
            rwLock.writeLock().unlock();
        }
    }

    public int getValue() {
        rwLock.readLock().lock();
        try {
            return value;
        } finally {
            rwLock.readLock().unlock();
        }
    }
}

说明:
ReadWriteLock 允许多个读线程同时访问,但在写操作时互斥,可以提高并发性能。
适用于读多写少的场景。
4. 使用 StampedLock

package com.example;

import java.util.concurrent.locks.StampedLock;

public class StampedLockExample {
    private int value = 0;
    private final StampedLock lock = new StampedLock();

    public void increment() {
        long stamp = lock.writeLock();
        try {
            value++;
        } finally {
            lock.unlockWrite(stamp);
        }
    }

    public int getValue() {
        long stamp = lock.tryOptimisticRead();
        int currentValue = value;
        if (!lock.validate(stamp)) {
            stamp = lock.readLock();
            try {
                currentValue = value;
            } finally {
                lock.unlockRead(stamp);
            }
        }
        return currentValue;
    }
}

说明:
StampedLock 是一种改进的读写锁,提供了乐观读的功能,可以进一步提高并发性能。
适用于高并发读的场景,需要注意 validate 方法的使用。

总结
高并发主要应用于需要同时处理大量请求的系统,提升系统的吞吐量和响应能力。
并发锁在高并发场景下,用于保证数据的正确性和一致性,防止资源竞争和数据错乱。
常用的并发锁包括 synchronized、ReentrantLock、ReadWriteLock、StampedLock 等,根据不同的场景选择合适的锁机制。

在双十一这样的高并发场景下,提升分布式的性能通常需要从多个方面进行优化,以确保系统能够稳定高效地处理大量并发请求。以下是一些提升分布式性能的方法: 1. 粒度的控制:尽量减小的粒度,只在必要时使用,避免不必要的争用。例如,在分布式环境下,如果操作的是不同数据,则可以避免使用同一把。 2. 的优化:对于读多写少的场景,可以使用读写(如ReentrantReadWriteLock),允许多个读操作同时进行,但写操作时阻塞读操作,以此提高并发性能。 3. 分布式的实现选择:选择合适的分布式实现方式,比如基于Redis的RedLock算法、基于ZooKeeper的机制等。每种技术有其特点,如ZooKeeper适合读多写少的场景,而Redis适合读多写也多的场景。 4. 的过期策略:为设置合理的过期时间(TTL),确保在异常情况下能够自动释放,避免造成死。 5. 避免单点故障:使用高可用的分布式服务,如基于主从或集群的Redis,保证即使部分节点故障,整个系统依然能正常工作。 6. 减少网络通信:尽量减少分布式操作的网络通信次数,例如,可以将的获取和释放操作合并为一次网络请求。 7. 客户端优化:在客户端实现重试机制、超时机制,以及必要的限流措施,保证操作的高效和稳定。 8. 系统监控:加强相关的监控和告警,及时发现性能瓶颈和潜在的问题。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值