多线程LOCK被占用如何让其他线程不等待?

在 C# 中,当使用 lock 关键字时,默认情况下其他线程如果遇到锁被占用会进入等待状态。若要让其他线程在锁被占用时不等待,可以通过以下几种方式实现:

  1. 使用 Monitor.TryEnter 方法
    Monitor.TryEnter 方法尝试获取指定对象上的排他锁,若锁可用则获取锁并返回 true,若锁已被其他线程持有则立即返回 false,而不会让线程进入等待状态。
    using System;
    using System.Threading;
    using System.Threading.Tasks;

class Program
{
private static readonly object lockObject = new object();

static void Main()
{
    // 创建多个任务来尝试获取锁
    Task[] tasks = new Task[3];
    for (int i = 0; i < 3; i++)
    {
        int taskId = i;
        tasks[i] = Task.Run(() => TryAccessSharedResource(taskId));
    }

    // 等待所有任务完成
    Task.WaitAll(tasks);
}

static void TryAccessSharedResource(int taskId)
{
    if (Monitor.TryEnter(lockObject))
    {
        try
        {
            Console.WriteLine($"Task {taskId} acquired the lock and is accessing the shared resource.");
            // 模拟一些耗时操作
            Thread.Sleep(2000);
        }
        finally
        {
            Monitor.Exit(lockObject);
            Console.WriteLine($"Task {taskId} released the lock.");
        }
    }
    else
    {
        Console.WriteLine($"Task {taskId} could not acquire the lock and will not wait.");
    }
}

}
代码解释
Monitor.TryEnter(lockObject) 尝试获取 lockObject 上的锁。
如果返回 true,则进入 try 块执行受保护的代码,完成后在 finally 块中调用 Monitor.Exit(lockObject) 释放锁。
如果返回 false,则执行 else 块中的代码,表明该线程未能获取锁且不会等待。
2. 使用 ReaderWriterLockSlim
ReaderWriterLockSlim 是一个更灵活的同步原语,它允许多个线程同时进行读操作,但在进行写操作时需要独占锁。可以使用 TryEnterWriteLock 或 TryEnterReadLock 方法来尝试获取锁,若锁不可用则立即返回 false。
示例代码
using System;
using System.Threading;
using System.Threading.Tasks;

class Program
{
private static readonly ReaderWriterLockSlim rwLock = new ReaderWriterLockSlim();

static void Main()
{
    // 创建多个任务来尝试获取写锁
    Task[] tasks = new Task[3];
    for (int i = 0; i < 3; i++)
    {
        int taskId = i;
        tasks[i] = Task.Run(() => TryAccessWithWriteLock(taskId));
    }

    // 等待所有任务完成
    Task.WaitAll(tasks);
}

static void TryAccessWithWriteLock(int taskId)
{
    if (rwLock.TryEnterWriteLock(0))
    {
        try
        {
            Console.WriteLine($"Task {taskId} acquired the write lock and is accessing the shared resource.");
            // 模拟一些耗时操作
            Thread.Sleep(2000);
        }
        finally
        {
            rwLock.ExitWriteLock();
            Console.WriteLine($"Task {taskId} released the write lock.");
        }
    }
    else
    {
        Console.WriteLine($"Task {taskId} could not acquire the write lock and will not wait.");
    }
}

}
代码解释
rwLock.TryEnterWriteLock(0) 尝试获取写锁,参数 0 表示不等待,若锁不可用则立即返回 false。
如果成功获取写锁,进入 try 块执行写操作,完成后在 finally 块中调用 rwLock.ExitWriteLock() 释放写锁。
如果未能获取写锁,执行 else 块中的代码,表明该线程不会等待
3. 使用 ConcurrentDictionary 等并发集合
对于一些常见的共享数据结构操作,如字典的读写操作,可以使用 ConcurrentDictionary 等并发集合,它们内部实现了线程安全机制,不需要手动加锁,并且在操作冲突时不会让线程进入等待状态。
示例代码
using System;
using System.Collections.Concurrent;
using System.Threading.Tasks;

class Program
{
private static readonly ConcurrentDictionary<int, string> concurrentDict = new ConcurrentDictionary<int, string>();

static void Main()
{
    // 创建多个任务来尝试添加元素到并发字典
    Task[] tasks = new Task[3];
    for (int i = 0; i < 3; i++)
    {
        int taskId = i;
        tasks[i] = Task.Run(() => TryAddToConcurrentDictionary(taskId));
    }

    // 等待所有任务完成
    Task.WaitAll(tasks);
}

static void TryAddToConcurrentDictionary(int taskId)
{
    if (concurrentDict.TryAdd(taskId, $"Value {taskId}"))
    {
        Console.WriteLine($"Task {taskId} successfully added an element to the concurrent dictionary.");
    }
    else
    {
        Console.WriteLine($"Task {taskId} failed to add an element to the concurrent dictionary.");
    }
}

}
代码解释
concurrentDict.TryAdd(taskId, $“Value {taskId}”) 尝试向 ConcurrentDictionary 中添加元素,若添加成功则返回 true,若键已存在则返回 false,不会让线程等待。
通过上述方法,可以实现让其他线程在锁被占用时不等待的需求。不同的场景可以选择合适的同步机制来提高程序的性能和响应能力。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值