C# 好狂的多线程呀
ThreadStart 和 ParameterizedThreadStart 是不是必须的?
在创建线程时:创建不带参数的线程可用 ThreadStart;创建带一个 object 参数的线程可用 ParameterizedThreadStart。但有时我们看到有些人的代码又没有用这两个。其实都是正确的,因为从
.NET 2.0 开始 ThreadStart、ParameterizedThreadStart 就可以省略了,.NET 会自动去寻找合适的委托。
So : 一般情况下不用指定ThreadStart/ParameterizedThreadStart,除非重载,否则直接public void pp(object obj){...}
object类型接收参数,会自动化匹配的。 线程函数要么没有参数,要么只能有一个object参数,而且均void ----------------------------------------------------------------------------线程基本操作
向线程传递参数
**新线程调用当前Class中的方法并传入多参(object)--List<>带多参**
class Program
{
static void Main(string[] args)
{
List<string> List = new List<string>();
List.Add("姜佳泉");
List.Add("hhh");
Thread t = new Thread(pp);
t.Start(List);//线程开始执行
Console.ReadKey();
}
public static void pp(object obj)
{
List<string> ll = (List<string>)obj;
for (int i = 0; i < ll.Count; i++)
{
Console.WriteLine(ll[i]);
}
}
}
**新线程调用其他Class中的方法并传入多参(object)--List<>带多参**
class Program
{
static void Main(string[] args)
{
List<string> List = new List<string>();
List.Add("姜佳泉");
List.Add("hhh");
aa a = new aa();
Thread t = new Thread(a.pp);
t.Start(List);//线程开始执行
Console.ReadKey();
}
}
class aa
{
public void pp(object obj)//坑:非静态模式
{
List<string> ll = (List<string>)obj;
for (int i = 0; i < ll.Count; i++)
{
Console.WriteLine(ll[i]);
}
}
}
**新线程调用其他Class中的方法并传入多参(object)+构造函数传参=两种方式可单用也可一起用**
class Program
{
static void Main(string[] args)
{
List<string> List = new List<string>();
List.Add("姜佳泉");
List.Add("hhh");
aa a = new aa();
a.a = "aaaa";
a.b = "bbbb";
Thread t = new Thread(new ParameterizedThreadStart(a.pp));
t.Start(List);//线程开始执行
Console.ReadKey();
}
}
class aa
{
public string a;
public string b;
public string A { get => a; set => a = value; }
public string B { get => b; set => b = value; }
public void pp(object obj)
{
Console.WriteLine(a);
Console.WriteLine(b);
List<string> ll = (List<string>)obj;
for (int i = 0; i < ll.Count; i++)
{
Console.WriteLine(ll[i]);
}
}
}
**骚操作~~~**
class Program
{
static void Main(string[] args)
{
ThreadStart threadStartDelegate = new ThreadStart(Work.DoWork); //创建委托
Thread thread = new Thread(threadStartDelegate); //用ThreadStart委托实例化线程Thread
thread.Start();
Work work = new Work();
work.Data = 42;
threadStartDelegate = new ThreadStart(work.DoMoreWork);
thread = new Thread(threadStartDelegate);
thread.Start();
Console.ReadKey();
}
public class Work
{
public static void DoWork()
{
Console.WriteLine(Thread.CurrentThread.ManagedThreadId.ToString());
}
public int Data;
public void DoMoreWork()
{
Console.WriteLine(Thread.CurrentThread.ManagedThreadId.ToString(),Data);
}
}
}
**委托累加方法(+=),投入线程中,顺序运行累加的方法**
class Program
{
static void Main(string[] args)
{
Work work = new Work();//首先对象实例化
work.a = 1;
ThreadStart threadStartDelegate = new ThreadStart(work.aa);//创建委托
work.b = 2;
threadStartDelegate += new ThreadStart(work.bb);//委托累加方法work.bb +=
work.c = 3;
threadStartDelegate += new ThreadStart(work.cc);//委托累加方法work.cc +=
Thread thread = new Thread(threadStartDelegate);//创建线程Thread,将threadStartDelegate委托(已累加三个方法)丢进线程Thread中
thread.Start();//线程开始
Console.ReadKey();
}
public class Work
{
public int a;
public int b;
public int c;
public void aa()
{
Console.WriteLine(a);
}
public void bb()
{
Console.WriteLine(b);
}
public void cc()
{
Console.WriteLine(c);
}
}
}
锁住对象,顺序执行,避免竞争,线程同步--lock(Monitor)-Mutex-Interlocked-ReaderWriterLock
https://blog.csdn.net/qq_42537006/article/details/104949841?utm_medium=distribute.pc_relevant.none-task-blog-BlogCommendFromBaidu-1.nonecase&depth_1-utm_source=distribute.pc_relevant.none-task-blog-BlogCommendFromBaidu-1.nonecase
https://www.cnblogs.com/StupidsCat/archive/2013/01/07/2849482.html
https://www.cnblogs.com/michaelxu/archive/2008/09/20/1293716.html
https://www.cnblogs.com/yy1234/p/7691075.html
https://blog.csdn.net/esonbest1234/article/details/50729511
------------------------------------------------------------------------------------------------------
**lock:**
**当前代码块只能被一个线程调用,直到用完后才可以被其他线程调用:模拟连续转账:即高并发**
**有多个线程创建并执行,但是运行结果是一个一个执行完**
class Program
{
static void Main(string[] args)
{
aa a = new aa();
for (int i = 0; i < 10; i++)
{
Thread t = new Thread(a.Work);
t.Start(i);
}
Console.Read();
}
}
class aa
{
public void Work(object i)
{
lock (this)
{
Console.WriteLine("我是线程:{0}", (int)i);
Thread.Sleep(100); //避免线程瞬间执行完成
}
}
}
特别说明
1.lock语句中锁定的必须是引用类型的对象,不能是值类型
2.为了避免死锁,lock的对象需要是private对象
3.为了避免lock对象的唯一性,通lock的对象为 private static或者 private readonly static
1、如果一个类的实例是public的,最好不要lock(this)。因为使用你的类的人也许不知道你用了lock,如果他new了一个实例,并且对这个实例上锁,就很容易造成死锁。
2、如果MyType是public的,不要lock(typeof(MyType))。
3、永远也不要lock一个字符串。
public void Function()
{
object lockThis = new object ();
lock (lockThis)
{
// Access thread-sensitive resources.
}
}
------------------------------------------------------------------------------------------------------
**Monitor**
https://www.cnblogs.com/hehexiaoxia/p/4064741.html
限时结束进程,避免锁死:
当调用了Monitor的Enter(Object o)方法时,会获取o的独占权,直到调用Exit(Object o)方法时,才会释放对o的独占权,可以多次调用Enter(Object o)方法,只需要调用同样次数的Exit(Object o)方法即可,Monitor类同时提供了TryEnter(Object o,[int])的一个重载方法,该方法尝试获取o对象的独占权,当获取独占权失败时,将返回false。
----
使用 TryEnter() 方法可以给它传送一个超时值,决定等待获得对象锁的最长时间。
使用 TryEnter() 方法设置获得对象锁的时间的代码如下。
Monitor.TryEnter(object, 毫秒数 );
该方法能在指定的毫秒数内结束线程,这样能避免线程之间的死锁现象。
lock (x)
{
DoSomething();
}
等效于
object obj = ( object )x;
System.Threading.Monitor.Enter(obj);
try
{
DoSomething();
}
finally
{
System.Threading.Monitor.Exit(obj);//释放资源
}
Enter(Object) 在指定对象上获取排他锁。
Exit(Object) 释放指定对象上的排他锁。
IsEntered 确定当前线程是否保留指定对象锁。
Pulse 通知等待队列中的线程锁定对象状态的更改。
PulseAll 通知所有的等待线程对象状态的更改。
TryEnter(Object) 试图获取指定对象的排他锁。
TryEnter(Object, Boolean) 尝试获取指定对象上的排他锁,并自动设置一个值,指示是否得到了该锁。
Wait(Object) 释放对象上的锁并阻止当前线程,直到它重新获取该锁。
------------------------------------------------------------------------------------------------------
**Mutex互斥锁*
https://blog.csdn.net/weixin_41049188/article/details/100085420
Mutex类是win32封装的,所以它所需要的互操作转换更耗资源。
Mutex是跨进程的,因此我们可以在同一台机器甚至远程的机器上的多个进程上使用同一个互斥体。
如果当前有一个线程拥有它,在没有释放之前,其它线程是没有权利拥有它的。我们可以把Mutex看作洗手间,上厕所的人看作线程;上厕所的人先进洗手间,拥有使用权,上完厕所之后出来,把洗手间释放,其他人才可以使用。
线程使用Mutex.WaitOne()方法等待C# Mutex对象被释放,如果它等待的C# Mutex对象被释放了,它就自动拥有这个对象,直到它调用Mutex.ReleaseMutex()方法释放这个对象,而在此期间,其他想要获取这个C# Mutex对象的线程都只有等待。
我们可以利用这个特性来控制一个应用程序只能运行一个实例。其他实例由于得不到这个Mutex而不能运行。
通过Mutex的使用很容易就解决了窗体实例化重复的问题,
------------------------------------------------------------------------------------------------------
**Interlocked原子操作**
为多个线程共享的变量提供原子操作。
使用 Interlocked 类,可以在不阻塞线程(lock、Monitor)的情况下,避免竞争条件。
Interlocked类主要方法:https://www.whuanle.cn/archives/885
方法 | 作用 |
---|---|
CompareExchange() | 比较两个数是否相等,如果相等,则替换第一个值。 |
Decrement() | 以原子操作的形式递减指定变量的值并存储结果。 |
Exchange() | 以原子操作的形式,设置为指定的值并返回原始值。 |
Increment() | 以原子操作的形式递增指定变量的值并存储结果。 |
Add() | 对两个数进行求和并用和替换第一个整数,上述操作作为一个原子操作完成。 |
Read() | 返回一个以原子操作形式加载的值。 |
------------------------------------------------------------------------------------------------------
**ReaderWriterLock资源访问**
在考虑资源访问的时候,惯性上我们会对资源实施lock机制,但是在某些情况下,我们仅仅需要读取资源的数据,而不是修改资源的数据,在这种情况下获取资源的独占权无疑会影响运行效率,因此.Net提供了一种机制,使用ReaderWriterLock进行资源访问时,如果在某一时刻资源并没有获取写的独占权,那么可以获得多个读的访问权,单个写入的独占权,如果某一时刻已经获取了写入的独占权,那么其它读取的访问权必须进行等待
ReaderWriteLock中主要用3组方法:https://www.cnblogs.com/mengluo/p/5599927.html
<1> AcquireWriterLock: 获取写入锁。
ReleaseWriterLock:释放写入锁。
<2> AcquireReaderLock: 获取读锁。
ReleaseReaderLock:释放读锁。
<3> UpgradeToWriterLock:将读锁转为写锁。
DowngradeFromWriterLock:将写锁还原为读锁。
并发,并行,串行,同步,异步?
BeginInvoke与EndInvoke/多线程接收委托返回值/委托的同步调用和异步调用
http://blog.sina.com.cn/s/blog_6e51df7f0100ss10.html
http://www.sufeinet.com/thread-3707-1-1.html
https://www.cnblogs.com/yinhu435/archive/2009/10/19/1585958.html
https://www.cnblogs.com/renhaojie/archive/2009/09/10/1564052.html