1. 这篇是并发集合中的最后一篇,介绍一下BlockingCollection。在工作中我还没有使用过,但是看上去应该是为了便捷使用并发集合而创建的类型。默认情况下,BlockingCollection使用的是ConcurrentQueue容器,当然我们也可以使用其他实现了IProducerConsumerCollection的类型来操作。
  2.  
  3. static Task GetRandomDelay()
  4. {
  5. int delay = new Random(DateTime.Now.Millisecond).Next(1, 500);
  6. return Task.Delay(delay);
  7. }
  8.  
  9. class CustomTask
  10. {
  11. public int Id { get; set; }
  12. }
  13.  
  14. static async Task RunProgram(IProducerConsumerCollection<CustomTask> collection = null)
  15. {
  16. var taskCollection = new BlockingCollection<CustomTask>();
  17. if(collection != null)
  18. taskCollection= new BlockingCollection<CustomTask>(collection);
  19.  
  20. var taskSource = Task.Run(() => TaskProducer(taskCollection));
  21.  
  22. Task[] processors = new Task[4];
  23. for (int i = 1; i <= 4; i++)
  24. {
  25. string processorId = "Processor " + i;
  26. processors[i - 1] = Task.Run(() => TaskProcessor(taskCollection, processorId));
  27. }
  28.  
  29. await taskSource;
  30.  
  31. await Task.WhenAll(processors);
  32. }
  33.  
  34. static async Task TaskProducer(BlockingCollection<CustomTask> collection)
  35. {
  36. for (int i = 1; i <= 20; i++)
  37. {
  38. await Task.Delay(20);
  39. var workItem = new CustomTask { Id = i };
  40. collection.Add(workItem);
  41. Console.WriteLine("Task {0} has been posted", workItem.Id);
  42. }
  43. collection.CompleteAdding(); //完成工作
  44. }
  45.  
  46. static async Task TaskProcessor(BlockingCollection<CustomTask> collection, string name)
  47. {
  48. await GetRandomDelay();
  49. foreach (CustomTask item in collection.GetConsumingEnumerable())
  50. {
  51. Console.WriteLine("Task {0} has been processed by {1}", item.Id, name);
  52. await GetRandomDelay();
  53. }
  54. }
  55.  
  56. 首先调用默认的BlockingCollection
  57.  
  58. 然后我们传入一个ConcurrentStack实例
  59.  
  60. Console.WriteLine("Using a Stack inside of BlockingCollection");
  61. Console.WriteLine();
  62. Task t = RunProgram(new ConcurrentStack<CustomTask>());
  63. t.Wait();
  1. C# 并行编程 之 并发集合 (.Net Framework 4.0)
  2. 20150508 10:15:29 zy__ 阅读数 24909更多
  3. 分类专栏: C#
  4. 版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
  5. 本文链接:https://blog.csdn.net/wangzhiyu1980/article/details/45497907
  6. 此文为个人学习《C#并行编程高级教程》的笔记,总结并调试了一些文章中的代码示例。 在以后开发过程中可以加以运用。
  7.  
  8. 对于并行任务,与其相关紧密的就是对一些共享资源,数据结构的并行访问。经常要做的就是对一些队列进行加锁-解锁,然后执行类似插入,删除等等互斥操作。 .NetFramework 4.0 中提供了一些封装好的支持并行操作数据容器,可以减少并行编程的复杂程度。
  9.  
  10. 基本信息
  11. .NetFramework中并行集合的名字空间: System.Collections.Concurrent
  12.  
  13. 并行容器:
  14.  
  15. ConcurrentQueue
  16. ConcurrentStack
  17. ConcurrentBag 一个无序的数据结构集,当不需要考虑顺序时非常有用。
  18. BlockingCollection 与经典的阻塞队列数据结构类似
  19. ConcurrentDictionary
  20.  
  21. 这些集合在某种程度上使用了无锁技术(CAS Compare-and-Swap和内存屏障 Memory Barrier),与加互斥锁相比获得了性能的提升。但在串行程序中,最好不用这些集合,它们必然会影响性能。
  22.  
  23. 关于CAS:
  24. http://www.tuicool.com/articles/zuui6z
  25. http://www.360doc.com/content/11/0914/16/7656248_148221200.shtml
  26. 关于内存屏障
  27. http://en.wikipedia.org/wiki/Memory_barrier
  28.  
  29. 用法与示例
  30. ConcurrentQueue
  31. 其完全无锁,但当CAS面临资源竞争失败时可能会陷入自旋并重试操作。
  32.  
  33. Enqueue:在队尾插入元素
  34. TryDequeue:尝试删除队头元素,并通过out参数返回
  35. TryPeek:尝试将对头元素通过out参数返回,但不删除该元素。
  36.  
  37. 程序示例:
  38.  
  39. using System;
  40. using System.Text;
  41.  
  42. using System.Threading.Tasks;
  43. using System.Collections.Concurrent;
  44.  
  45. namespace Sample4_1_concurrent_queue
  46. {
  47. class Program
  48. {
  49. internal static ConcurrentQueue<int> _TestQueue;
  50.  
  51. class ThreadWork1 // producer
  52. {
  53. public ThreadWork1()
  54. { }
  55.  
  56. public void run()
  57. {
  58. System.Console.WriteLine("ThreadWork1 run { ");
  59. for (int i = 0; i < 100; i++)
  60. {
  61. System.Console.WriteLine("ThreadWork1 producer: " + i);
  62. _TestQueue.Enqueue(i);
  63. }
  64. System.Console.WriteLine("ThreadWork1 run } ");
  65. }
  66. }
  67.  
  68. class ThreadWork2 // consumer
  69. {
  70. public ThreadWork2()
  71. { }
  72.  
  73. public void run()
  74. {
  75. int i = 0;
  76. bool IsDequeuue = false;
  77. System.Console.WriteLine("ThreadWork2 run { ");
  78. for (; ; )
  79. {
  80. IsDequeuue = _TestQueue.TryDequeue(out i);
  81. if (IsDequeuue)
  82. System.Console.WriteLine("ThreadWork2 consumer: " + i * i + " =====");
  83.  
  84. if (i == 99)
  85. break;
  86. }
  87. System.Console.WriteLine("ThreadWork2 run } ");
  88. }
  89. }
  90.  
  91. static void StartT1()
  92. {
  93. ThreadWork1 work1 = new ThreadWork1();
  94. work1.run();
  95. }
  96.  
  97. static void StartT2()
  98. {
  99. ThreadWork2 work2 = new ThreadWork2();
  100. work2.run();
  101. }
  102. static void Main(string[] args)
  103. {
  104. Task t1 = new Task(() => StartT1());
  105. Task t2 = new Task(() => StartT2());
  106.  
  107. _TestQueue = new ConcurrentQueue<int>();
  108.  
  109. Console.WriteLine("Sample 3-1 Main {");
  110.  
  111. Console.WriteLine("Main t1 t2 started {");
  112. t1.Start();
  113. t2.Start();
  114. Console.WriteLine("Main t1 t2 started }");
  115.  
  116. Console.WriteLine("Main wait t1 t2 end {");
  117. Task.WaitAll(t1, t2);
  118. Console.WriteLine("Main wait t1 t2 end }");
  119.  
  120. Console.WriteLine("Sample 3-1 Main }");
  121.  
  122. Console.ReadKey();
  123. }
  124. }
  125. }
  126.  
  127. ConcurrentStack
  128. 其完全无锁,但当CAS面临资源竞争失败时可能会陷入自旋并重试操作。
  129.  
  130. Push:向栈顶插入元素
  131. TryPop:从栈顶弹出元素,并且通过out 参数返回
  132. TryPeek:返回栈顶元素,但不弹出。
  133.  
  134. 程序示例:
  135.  
  136. using System;
  137. using System.Text;
  138.  
  139. using System.Threading.Tasks;
  140. using System.Collections.Concurrent;
  141.  
  142. namespace Sample4_2_concurrent_stack
  143. {
  144. class Program
  145. {
  146. internal static ConcurrentStack<int> _TestStack;
  147.  
  148. class ThreadWork1 // producer
  149. {
  150. public ThreadWork1()
  151. { }
  152.  
  153. public void run()
  154. {
  155. System.Console.WriteLine("ThreadWork1 run { ");
  156. for (int i = 0; i < 100; i++)
  157. {
  158. System.Console.WriteLine("ThreadWork1 producer: " + i);
  159. _TestStack.Push(i);
  160. }
  161. System.Console.WriteLine("ThreadWork1 run } ");
  162. }
  163. }
  164.  
  165. class ThreadWork2 // consumer
  166. {
  167. public ThreadWork2()
  168. { }
  169.  
  170. public void run()
  171. {
  172. int i = 0;
  173. bool IsDequeuue = false;
  174. System.Console.WriteLine("ThreadWork2 run { ");
  175. for (; ; )
  176. {
  177. IsDequeuue = _TestStack.TryPop(out i);
  178. if (IsDequeuue)
  179. System.Console.WriteLine("ThreadWork2 consumer: " + i * i + " =====" + i);
  180.  
  181. if (i == 99)
  182. break;
  183. }
  184. System.Console.WriteLine("ThreadWork2 run } ");
  185. }
  186. }
  187.  
  188. static void StartT1()
  189. {
  190. ThreadWork1 work1 = new ThreadWork1();
  191. work1.run();
  192. }
  193.  
  194. static void StartT2()
  195. {
  196. ThreadWork2 work2 = new ThreadWork2();
  197. work2.run();
  198. }
  199. static void Main(string[] args)
  200. {
  201. Task t1 = new Task(() => StartT1());
  202. Task t2 = new Task(() => StartT2());
  203.  
  204. _TestStack = new ConcurrentStack<int>();
  205.  
  206. Console.WriteLine("Sample 4-1 Main {");
  207.  
  208. Console.WriteLine("Main t1 t2 started {");
  209. t1.Start();
  210. t2.Start();
  211. Console.WriteLine("Main t1 t2 started }");
  212.  
  213. Console.WriteLine("Main wait t1 t2 end {");
  214. Task.WaitAll(t1, t2);
  215. Console.WriteLine("Main wait t1 t2 end }");
  216.  
  217. Console.WriteLine("Sample 4-1 Main }");
  218.  
  219. Console.ReadKey();
  220. }
  221. }
  222. }
  223.  
  224. 测试中一个有趣的现象:
  225.  
  226. 虽然生产者已经在栈中插入值已经到了25,但消费者第一个出栈的居然是4,而不是25。很像是出错了。但仔细想想入栈,出栈和打印语句是两个部分,而且并不是原子操作,出现这种现象应该也算正常。
  227.  
  228. Sample 3-1 Main {
  229. Main t1 t2 started {
  230. Main t1 t2 started }
  231. Main wait t1 t2 end {
  232. ThreadWork1 run {
  233. ThreadWork1 producer: 0
  234. ThreadWork2 run {
  235. ThreadWork1 producer: 1
  236. ThreadWork1 producer: 2
  237. ThreadWork1 producer: 3
  238. ThreadWork1 producer: 4
  239. ThreadWork1 producer: 5
  240. ThreadWork1 producer: 6
  241. ThreadWork1 producer: 7
  242. ThreadWork1 producer: 8
  243. ThreadWork1 producer: 9
  244. ThreadWork1 producer: 10
  245. ThreadWork1 producer: 11
  246. ThreadWork1 producer: 12
  247. ThreadWork1 producer: 13
  248. ThreadWork1 producer: 14
  249. ThreadWork1 producer: 15
  250. ThreadWork1 producer: 16
  251. ThreadWork1 producer: 17
  252. ThreadWork1 producer: 18
  253. ThreadWork1 producer: 19
  254. ThreadWork1 producer: 20
  255. ThreadWork1 producer: 21
  256. ThreadWork1 producer: 22
  257. ThreadWork1 producer: 23
  258. ThreadWork1 producer: 24
  259. ThreadWork1 producer: 25
  260. ThreadWork2 consumer: 16 =====4
  261. ThreadWork2 consumer: 625 =====25
  262. ThreadWork2 consumer: 576 =====24
  263. ThreadWork2 consumer: 529 =====23
  264. ThreadWork1 producer: 26
  265. ThreadWork1 producer: 27
  266. ThreadWork1 producer: 28
  267.  
  268. ConcurrentBag
  269. 一个无序的集合,程序可以向其中插入元素,或删除元素。
  270. 在同一个线程中向集合插入,删除元素的效率很高。
  271.  
  272. Add:向集合中插入元素 TryTake:从集合中取出元素并删除 TryPeek:从集合中取出元素,但不删除该元素。
  273.  
  274. 程序示例:
  275.  
  276. using System;
  277. using System.Text;
  278.  
  279. using System.Threading.Tasks;
  280. using System.Collections.Concurrent;
  281.  
  282. namespace Sample4_3_concurrent_bag
  283. {
  284. class Program
  285. {
  286. internal static ConcurrentBag<int> _TestBag;
  287.  
  288. class ThreadWork1 // producer
  289. {
  290. public ThreadWork1()
  291. { }
  292.  
  293. public void run()
  294. {
  295. System.Console.WriteLine("ThreadWork1 run { ");
  296. for (int i = 0; i < 100; i++)
  297. {
  298. System.Console.WriteLine("ThreadWork1 producer: " + i);
  299. _TestBag.Add(i);
  300. }
  301. System.Console.WriteLine("ThreadWork1 run } ");
  302. }
  303. }
  304.  
  305. class ThreadWork2 // consumer
  306. {
  307. public ThreadWork2()
  308. { }
  309.  
  310. public void run()
  311. {
  312. int i = 0;
  313. int nCnt = 0;
  314. bool IsDequeuue = false;
  315. System.Console.WriteLine("ThreadWork2 run { ");
  316. for (;;)
  317. {
  318. IsDequeuue = _TestBag.TryTake(out i);
  319. if (IsDequeuue)
  320. {
  321. System.Console.WriteLine("ThreadWork2 consumer: " + i * i + " =====" + i);
  322. nCnt++;
  323. }
  324.  
  325. if (nCnt == 99)
  326. break;
  327. }
  328. System.Console.WriteLine("ThreadWork2 run } ");
  329. }
  330. }
  331.  
  332. static void StartT1()
  333. {
  334. ThreadWork1 work1 = new ThreadWork1();
  335. work1.run();
  336. }
  337.  
  338. static void StartT2()
  339. {
  340. ThreadWork2 work2 = new ThreadWork2();
  341. work2.run();
  342. }
  343. static void Main(string[] args)
  344. {
  345. Task t1 = new Task(() => StartT1());
  346. Task t2 = new Task(() => StartT2());
  347.  
  348. _TestBag = new ConcurrentBag<int>();
  349.  
  350. Console.WriteLine("Sample 4-3 Main {");
  351.  
  352. Console.WriteLine("Main t1 t2 started {");
  353. t1.Start();
  354. t2.Start();
  355. Console.WriteLine("Main t1 t2 started }");
  356.  
  357. Console.WriteLine("Main wait t1 t2 end {");
  358. Task.WaitAll(t1, t2);
  359. Console.WriteLine("Main wait t1 t2 end }");
  360.  
  361. Console.WriteLine("Sample 4-3 Main }");
  362.  
  363. Console.ReadKey();
  364. }
  365. }
  366. }
  367.  
  368. BlockingCollection
  369. 一个支持界限和阻塞的容器
  370.  
  371. Add :向容器中插入元素
  372. TryTake:从容器中取出元素并删除
  373. TryPeek:从容器中取出元素,但不删除。
  374. CompleteAdding:告诉容器,添加元素完成。此时如果还想继续添加会发生异常。
  375. IsCompleted:告诉消费线程,生产者线程还在继续运行中,任务还未完成。
  376.  
  377. 示例程序:
  378.  
  379. 程序中,消费者线程完全使用 while (!_TestBCollection.IsCompleted) 作为退出运行的判断条件。
  380. Worker1中,有两条语句被注释掉了,当i 50时设置CompleteAdding,但当继续向其中插入元素时,系统抛出异常,提示无法再继续插入。
  381.  
  382. using System;
  383. using System.Text;
  384.  
  385. using System.Threading.Tasks;
  386. using System.Collections.Concurrent;
  387.  
  388. namespace Sample4_4_concurrent_bag
  389. {
  390. class Program
  391. {
  392. internal static BlockingCollection<int> _TestBCollection;
  393.  
  394. class ThreadWork1 // producer
  395. {
  396. public ThreadWork1()
  397. { }
  398.  
  399. public void run()
  400. {
  401. System.Console.WriteLine("ThreadWork1 run { ");
  402. for (int i = 0; i < 100; i++)
  403. {
  404. System.Console.WriteLine("ThreadWork1 producer: " + i);
  405. _TestBCollection.Add(i);
  406. //if (i == 50)
  407. // _TestBCollection.CompleteAdding();
  408. }
  409. _TestBCollection.CompleteAdding();
  410.  
  411. System.Console.WriteLine("ThreadWork1 run } ");
  412. }
  413. }
  414.  
  415. class ThreadWork2 // consumer
  416. {
  417. public ThreadWork2()
  418. { }
  419.  
  420. public void run()
  421. {
  422. int i = 0;
  423. int nCnt = 0;
  424. bool IsDequeuue = false;
  425. System.Console.WriteLine("ThreadWork2 run { ");
  426. while (!_TestBCollection.IsCompleted)
  427. {
  428. IsDequeuue = _TestBCollection.TryTake(out i);
  429. if (IsDequeuue)
  430. {
  431. System.Console.WriteLine("ThreadWork2 consumer: " + i * i + " =====" + i);
  432. nCnt++;
  433. }
  434. }
  435. System.Console.WriteLine("ThreadWork2 run } ");
  436. }
  437. }
  438.  
  439. static void StartT1()
  440. {
  441. ThreadWork1 work1 = new ThreadWork1();
  442. work1.run();
  443. }
  444.  
  445. static void StartT2()
  446. {
  447. ThreadWork2 work2 = new ThreadWork2();
  448. work2.run();
  449. }
  450. static void Main(string[] args)
  451. {
  452. Task t1 = new Task(() => StartT1());
  453. Task t2 = new Task(() => StartT2());
  454.  
  455. _TestBCollection = new BlockingCollection<int>();
  456.  
  457. Console.WriteLine("Sample 4-4 Main {");
  458.  
  459. Console.WriteLine("Main t1 t2 started {");
  460. t1.Start();
  461. t2.Start();
  462. Console.WriteLine("Main t1 t2 started }");
  463.  
  464. Console.WriteLine("Main wait t1 t2 end {");
  465. Task.WaitAll(t1, t2);
  466. Console.WriteLine("Main wait t1 t2 end }");
  467.  
  468. Console.WriteLine("Sample 4-4 Main }");
  469.  
  470. Console.ReadKey();
  471. }
  472. }
  473. }
  474.  
  475. 当然可以尝试在Work1中注释掉 CompleteAdding 语句,此时Work2陷入循环无法退出。
  476.  
  477. ConcurrentDictionary
  478. 对于读操作是完全无锁的,当很多线程要修改数据时,它会使用细粒度的锁。
  479.  
  480. AddOrUpdate:如果键不存在,方法会在容器中添加新的键和值,如果存在,则更新现有的键和值。
  481. GetOrAdd:如果键不存在,方法会向容器中添加新的键和值,如果存在则返回现有的值,并不添加新值。
  482. TryAdd:尝试在容器中添加新的键和值。
  483. TryGetValue:尝试根据指定的键获得值。
  484. TryRemove:尝试删除指定的键。
  485. TryUpdate:有条件的更新当前键所对应的值。
  486. GetEnumerator:返回一个能够遍历整个容器的枚举器。
  487.  
  488. 程序示例:
  489.  
  490. using System;
  491. using System.Text;
  492.  
  493. using System.Threading.Tasks;
  494. using System.Collections.Concurrent;
  495.  
  496. namespace Sample4_5_concurrent_dictionary
  497. {
  498. class Program
  499. {
  500. internal static ConcurrentDictionary<int, int> _TestDictionary;
  501.  
  502. class ThreadWork1 // producer
  503. {
  504. public ThreadWork1()
  505. { }
  506.  
  507. public void run()
  508. {
  509. System.Console.WriteLine("ThreadWork1 run { ");
  510. for (int i = 0; i < 100; i++)
  511. {
  512. System.Console.WriteLine("ThreadWork1 producer: " + i);
  513. _TestDictionary.TryAdd(i, i);
  514. }
  515.  
  516. System.Console.WriteLine("ThreadWork1 run } ");
  517. }
  518. }
  519.  
  520. class ThreadWork2 // consumer
  521. {
  522. public ThreadWork2()
  523. { }
  524.  
  525. public void run()
  526. {
  527. int i = 0, nCnt = 0;
  528. int nValue = 0;
  529. bool IsOk = false;
  530. System.Console.WriteLine("ThreadWork2 run { ");
  531. while (nCnt < 100)
  532. {
  533. IsOk = _TestDictionary.TryGetValue(i, out nValue);
  534. if (IsOk)
  535. {
  536. System.Console.WriteLine("ThreadWork2 consumer: " + i * i + " =====" + i);
  537. nValue = nValue * nValue;
  538. _TestDictionary.AddOrUpdate(i, nValue, (key, value) => { return value = nValue; });
  539. nCnt++;
  540. i++;
  541. }
  542. }
  543. System.Console.WriteLine("ThreadWork2 run } ");
  544. }
  545. }
  546.  
  547. static void StartT1()
  548. {
  549. ThreadWork1 work1 = new ThreadWork1();
  550. work1.run();
  551. }
  552.  
  553. static void StartT2()
  554. {
  555. ThreadWork2 work2 = new ThreadWork2();
  556. work2.run();
  557. }
  558. static void Main(string[] args)
  559. {
  560. Task t1 = new Task(() => StartT1());
  561. Task t2 = new Task(() => StartT2());
  562. bool bIsNext = true;
  563. int nValue = 0;
  564.  
  565. _TestDictionary = new ConcurrentDictionary<int, int>();
  566.  
  567. Console.WriteLine("Sample 4-5 Main {");
  568.  
  569. Console.WriteLine("Main t1 t2 started {");
  570. t1.Start();
  571. t2.Start();
  572. Console.WriteLine("Main t1 t2 started }");
  573.  
  574. Console.WriteLine("Main wait t1 t2 end {");
  575. Task.WaitAll(t1, t2);
  576. Console.WriteLine("Main wait t1 t2 end }");
  577.  
  578. foreach (var pair in _TestDictionary)
  579. {
  580. Console.WriteLine(pair.Key + " : " + pair.Value);
  581. }
  582.  
  583. System.Collections.Generic.IEnumerator<System.Collections.Generic.KeyValuePair<int, int>>
  584. enumer = _TestDictionary.GetEnumerator();
  585.  
  586. while (bIsNext)
  587. {
  588. bIsNext = enumer.MoveNext();
  589. Console.WriteLine("Key: " + enumer.Current.Key +
  590. " Value: " + enumer.Current.Value);
  591.  
  592. _TestDictionary.TryRemove(enumer.Current.Key, out nValue);
  593. }
  594.  
  595. Console.WriteLine("\n\nDictionary Count: " + _TestDictionary.Count);
  596.  
  597. Console.WriteLine("Sample 4-5 Main }");
  598.  
  599. Console.ReadKey();
  600. }
  601. }
  602. }
 

【C#】58. .Net中的并发集合——BlockingCollection的更多相关文章

  1. .Net多线程编程—并发集合

    并发集合 1 为什么使用并发集合? 原因主要有以下几点: System.Collections和System.Collections.Generic名称空间中所提供的经典列表.集合和数组都不是线程安全 ...

  2. C#并行编程-并发集合

    菜鸟学习并行编程,参考<C#并行编程高级教程.PDF>,如有错误,欢迎指正. 目录 C#并行编程-相关概念 C#并行编程-Parallel C#并行编程-Task C#并行编程-并发集合 ...

  3. 转载 .Net多线程编程—并发集合 https://www.cnblogs.com/hdwgxz/p/6258014.html

    集合 1 为什么使用并发集合? 原因主要有以下几点: System.Collections和System.Collections.Generic名称空间中所提供的经典列表.集合和数组都不是线程安全的, ...

  4. C#并发集合(转)

    出处:https://www.cnblogs.com/Leo_wl/p/6262749.html?utm_source=itdadao&utm_medium=referral 并发集合 1 为 ...

  5. C#并发集合

    并发集合   并发集合 1 为什么使用并发集合? 原因主要有以下几点: System.Collections和System.Collections.Generic名称空间中所提供的经典列表.集合和数组 ...

  6. java多线程中并发集合和同步集合有哪些?区别是什么?

    java多线程中并发集合和同步集合有哪些? hashmap 是非同步的,故在多线程中是线程不安全的,不过也可以使用 同步类来进行包装: 包装类Collections.synchronizedMap() ...

  7. .NET中的并发操作集合

    更新记录 本文迁移自Panda666原博客,原发布时间:2021年7月1日. 一.并发集合 .NET中提供了相当多线程安全的集合,它们都在System.Collections.Concurrent命名 ...

  8. JAVA并发七(多线程环境中安全使用集合API)

    在集合API中,最初设计的Vector和Hashtable是多线程安全的.例如:对于Vector来说,用来添加和删除元素的方法是同步的.如果只有一个线程与Vector的实例交互,那么,要求获取和释放对 ...

  9. 转:【Java并发编程】之八:多线程环境中安全使用集合API(含代码)

    转载请注明出处:http://blog.csdn.net/ns_code/article/details/17200509     在集合API中,最初设计的Vector和Hashtable是多线程安 ...

随机推荐

  1. VMWare虚拟机出现问题

    软件版本:VMware ESXi 5.5.0 服务器型号: Dell R720 问题经过: 某天ssh登录其中一个虚拟机,报错:kernel:BUG: soft lockup - CPU#6 stuc ...

  2. 编写合格的C代码(1):通过编译选项将特定警告视为错误

    目录 快速设定 向错误的执念开炮,向C编译器开炮 编译警告应当被忽略吗?warning不重要吗? 个人总结的应当视作error的warning 1. 函数没有声明就使用 2. 函数虽然有声明,但是声明 ...

  3. 简明conda使用指南

    目录 区分conda, anaconda, miniconda conda版本 虚拟环境 分享环境 查看某个环境的位置 列出软件包 安装软件包 删除软件包 查找软件包 conda配置 conda实践: ...

  4. UNITY Serializer 序列化 横向对比

    UNITY Serializer 序列化 横向对比 关于序列化,无论是.net还是unity自身都提供了一定保障.然而人总是吃着碗里想着锅里,跑去github挖个宝是常有的事.看看各家大佬的本事.最有 ...

  5. docker学习-qiang

    docker优势 轻量级.资源损耗少.启动快.性能高.只能运行linux系统 容器技术发展历程 1.chroot技术 新建一个子系统(拥有自己完整的系统文件) ldd /bin/ls(查看ls命令依赖 ...

  6. Io 异常: Invalid number format for port number

    报错信息: Caused by: java.sql.SQLException: Io 异常: Invalid number format for port number    at oracle.jd ...

  7. MacOS下IDEA设置智能提示不区分大小写

    本文只针对,IDEA-2019.2.3版本 目录地址: Edit -> General -> Code Completion -> Match case -> 勾选去掉 截图如 ...

  8. zzulioj - 2624: 小H的奇怪加法

    题目链接:http://acm.zzuli.edu.cn/problem.php?id=2624 题目描述 小H非常喜欢研究算法,尤其是各种加法.没错加法包含很多种,例如二进制中的全加,半加等.全加: ...

  9. PATA1028 List Sorting

    Excel can sort records according to any column. Now you are supposed to imitate this function. Input ...

  10. Django ORM性能优化 和 图片验证码

    一,ORM性能相关 1. 关联外键, 只拿一次数据 all_users = models.User.objects.all().values('name', 'age', 'role__name') ...