对于多线程不是很懂,面试的时候遇到一个多线程的题,不会做,分享出来,懂的大佬指点一下,谢谢
建一个winform窗体,在窗体中放上一个开始按钮,一个停止按钮,一个文本框,在窗体中声明一个List<int>类型的属性,点击开始按钮后开启10个线程,所有线程同时不间断的给List<int>集合中添加1-10000之间的随机数,要求添加List<int>集合中的数字不能重复,并且实时在文本框中显示集合的长度,当集合List<int>的长度等于1000时自动停止所有线程,如果中途点击停止按钮也停止所有线程,点击开始又继续执行。
添加的集合写成一个方法,所有线程来调用,方法里加lock,一边add一边检查是否到了1000,就行了,至于重复的问题,不同的线程add的数据分开来就行了,比如第一个线程1~1000,第二个线程 1001~2000,以此类推
至于中途停止的问题,加个全局变量就行了,通过检查变量break出for循环就好了
谢谢,知道怎么停止了
你的问题是什么?
我写了一个方法,准备创建十个线程调用方法,但是不知道怎么实现同时停止和继续。
Random rand = new Random();
int count = 0;
List<int> lis = new List<int>();
public void method()
{
while (true)
{
int num = rand.Next(0, 10001);
if (!lis.Contains(num))
{
lis.Add(num);
if (count < 1000)
{
count++;
textBox1.Text = count.ToString();
}
Thread.Sleep(100);
}
}
}
下面时开始按钮的事件,我循环开启了十个线程,但是停止按钮不知道怎么实现功能
private void button1_Click(object sender, EventArgs e)
{
for (int i = 0; i < 10; i++)
{
Thread t = new Thread(new ThreadStart(method));
t.Start();
}
}
using System;
using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;
namespace CSharpFundamental
{
class MultipleThreadCompete
{
List<int> numList = new List<int>();
CancellationTokenSource cts = new CancellationTokenSource();
private const int ENDNUM = 10000;
internal void DoTheCompeteSecond()
{
Task[] tasks = new Task[10];
for (int i = 0; i < 10; ++i)
{
int num = i;
tasks[i] = Task.Factory.StartNew(() => AddNumToList(num, cts), cts.Token);
}
Task.WaitAny(tasks);
}
private int GetTheListCount()
{
return numList.Count;
}
private void AddToList(int num)
{
if (numList.Count == ENDNUM)
{
return;
}
numList.Add(num);
}
private void AddNumToList(object state, CancellationTokenSource cts)
{
Console.WriteLine("This is the {0} thread,Current ThreadId={1}",
state,
Thread.CurrentThread.ManagedThreadId);
while (!cts.Token.IsCancellationRequested)
{
if (GetTheListCount() == ENDNUM)
{
cts.Cancel();
Console.WriteLine("Current Thread Id={0},Current Count={1}",
Thread.CurrentThread.ManagedThreadId,
GetTheListCount());
break;
}
var insertNum = GenerateInt32Num();
if (numList.Contains(insertNum))
{
insertNum = GenerateInt32Num();
}
AddToList(insertNum);
}
}
private int GenerateInt32Num()
{
Random random = new Random();
return random.Next(1, 10000);
}
}
}
Result:
写了一个较为简易 实现的 DEMO,用CancellationTokenSource 来实现取消Task, 使用 Task.WaitAny 用来返回任意执行完毕的 Task, 本来用 Parallel.Invoke 线程池来实现,但是不满足你的需求,没有创建 10 个线程,欢迎指点,交流。
楼上使用Random皆不是正确使用做法。
并发操作List也是错误的。
稍微严格点说用Task也是错误的。
只需要Thread 然后在循环中用条件判断就可完成暂停,至于取不重复的办法就很多了。
愿闻其详
@BUTTERAPPLE:
1.Random用一个实例;
2.List并发写->你设想这不是原子操作,那么其中2个“同时”取到的是一个地址引用会是什么结果;
3.池不等同于线程数量,池可以设置是2
@BUTTERAPPLE: 还有楼上不是只是指你,随便看了一下,包括顶顶上的code
@花飘水流兮:劳烦赐教,谢谢。我去研究一下。
@花飘水流兮: 使用 1 个线程池,让线程从线程池中自己分配,修改了一下代码
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Diagnostics;
using System.Threading;
using System.Threading.Tasks;
namespace CSharpFundamental
{
class MultipleThreadCompete
{
List<int> numList = new List<int>();
Random random = new Random();
CancellationTokenSource cts = new CancellationTokenSource();
private const int ENDNUM = 1000000;
ReaderWriterLockSlim rwls = new ReaderWriterLockSlim();
internal void DoTheCompeteSecond()
{
Stopwatch sw = new Stopwatch();
sw.Start();
Task[] tasks = new Task[100];
for (int i = 0; i < 100; ++i)
{
int num = i;
tasks[i] = Task.Run(() => AddNumToList(num, cts), cts.Token);
}
Task.WaitAny(tasks);
Console.WriteLine("ExecuteTime={0}", sw.ElapsedMilliseconds / 1000);
}
private int GetTheListCount()
{
return numList.Count;
}
private void AddToList(int num)
{
rwls.EnterReadLock();
if (numList.Count == ENDNUM)
return;
rwls.ExitReadLock();
rwls.EnterWriteLock();
numList.Add(num);
rwls.ExitWriteLock();
}
private void AddNumToList(object state, CancellationTokenSource cts)
{
Console.WriteLine("This is the {0} thread,Current ThreadId={1}",
state,
Thread.CurrentThread.ManagedThreadId);
while (!cts.Token.IsCancellationRequested)
{
try
{
rwls.EnterReadLock();
if (numList.Count == ENDNUM)
{
cts.Cancel();
Console.WriteLine("Current Thread Id={0},Current Count={1}",
Thread.CurrentThread.ManagedThreadId,
GetTheListCount());
break;
}
}
finally
{
rwls.ExitReadLock();
}
var insertNum = GenerateInt32Num();
if (numList.Contains(insertNum))
{
insertNum = GenerateInt32Num();
}
AddToList(insertNum);
}
}
private int GenerateInt32Num()
{
return random.Next(1, ENDNUM);
}
}
}
@花飘水流兮: ThreadPool.SetMinThreads(CURRENT_THREAD_COUNT, CURRENT_THREAD_COUNT); 分配最小线程即可实现所需要的线程数,但不推荐,即使建了那么多,可能更多的时间用在了 CPU 切换 上下文上了