zoukankan      html  css  js  c++  java
  • 在使用HttpClient做客户端调用一个API时 模拟并发调用时发生“死锁"?

    平时还是比较喜欢看书的。。但有时候遇到问题还是经常感到脑袋一蒙。。智商果然是硬伤。。

    同事发现了个问题,代码如下:

        class Program
        {
            static void Main(string[] args)
            {
                HttpClientClass c = new HttpClientClass();
                while (true)
                {
                    Task.Factory.StartNew(() =>
                    {
                        Console.WriteLine(Thread.CurrentThread.ManagedThreadId + "开始请求:" + DateTime.Now);
                        c.BeginGetMethod();
                    }, CancellationToken.None, TaskCreationOptions.None, TaskScheduler.Default);
                    System.Threading.Thread.Sleep(10 * 1);
                }
            }
        }
        public class HttpClientClass
        {
            private static readonly HttpClient c;
            static HttpClientClass()
            {
                c = new HttpClient();
                c.Timeout = TimeSpan.FromSeconds(15);
            }
            public void BeginGetMethod()
            {
                try
                {
                    var r = c.GetAsync("https://www.cnblogs.com/").Result;
                    if (r.IsSuccessStatusCode)
                        Console.WriteLine(Thread.CurrentThread.ManagedThreadId + "ok");
                    else
                        Console.WriteLine(Thread.CurrentThread.ManagedThreadId + "bad request");
                }
                catch (Exception ex)
                {
                    Console.WriteLine(ex.GetType().FullName);
                }
            }

    在使用HttpClient的GetAsync请求后阻塞查询.Result“死锁了”,我们知道GetAsync内部也是一个后台线程在执行,直到获取到结果时会调用Task中的SetResult方法,然后通过.Result就能回去结果了。。

    如果此处有问题,那我们假如做网站开发时,并发请求来了岂不是废掉了?!!

    当然不是这样。。实际上线程池中处理任务时是存在任务队列的(不提看源码的事。。看完就忘。。)此处大概意思就是:主线程创建线程任务时,任务优先级高于后台线程创建的线程。这里的while不停的创建后台任务就导致了GetAsync方法中的后台任务一直在等啊等。。所以就发生了所谓的"死锁"。。其实是根本就没机会执行。。(没涉及到线程上下文切换,所以谈到这也能发生死锁时脑袋一蒙。。)

    所以可以这么调用:

                Task.Factory.StartNew(() =>
                {
                    while (true)
                    {
                        Task.Factory.StartNew(() =>
                        {
                            Console.WriteLine(Thread.CurrentThread.ManagedThreadId + "开始请求:" + DateTime.Now);
                            c.BeginGetMethod();
                        }, CancellationToken.None, TaskCreationOptions.None, TaskScheduler.Default);
                        System.Threading.Thread.Sleep(10 * 1);
                    }
                });
  • 相关阅读:
    分享,如何激励程序员?
    [经验交流] (最新)移动App应用安全漏洞分析报告 !
    最全最热【资源汇总】Android应用解决方案全攻略
    最赚钱十大行业 网络编辑3G工程师入选
    分享:Android Studio 导入第三方jar包,重复加载错误解决办法。
    分享:怎么去测试一个 app 是否存在安全问题?
    Android系统刷机后第一次启动很慢的原因
    转载分享:Android APP二次打包操作步骤介绍
    Android开发之HelloWorld程序
    安卓源码总体结构(2)基础知识汇总
  • 原文地址:https://www.cnblogs.com/ylsforever/p/7503956.html
Copyright © 2011-2022 走看看