Lazy<T> 构造函数
定义
重要
一些信息与预发行产品相关,相应产品在发行之前可能会进行重大修改。 对于此处提供的信息,Microsoft 不作任何明示或暗示的担保。
初始化 Lazy<T> 类的新实例。
重载
Lazy<T>() |
初始化 Lazy<T> 类的新实例。 发生迟缓初始化时,使用目标类型的无参数构造函数。 |
Lazy<T>(Boolean) |
初始化 Lazy<T> 类的新实例。 发生迟缓初始化时,使用目标类型的无参数构造函数和指定的初始化模式。 |
Lazy<T>(Func<T>) |
初始化 Lazy<T> 类的新实例。 出现迟缓初始化时,将使用指定的初始化函数。 |
Lazy<T>(LazyThreadSafetyMode) |
初始化 Lazy<T> 类的新实例,其中使用 |
Lazy<T>(T) |
初始化 Lazy<T> 类的新实例,该类使用已预先初始化的指定值。 |
Lazy<T>(Func<T>, Boolean) |
初始化 Lazy<T> 类的新实例。 当延迟初始化发生时,将使用指定的初始化函数和初始化模式。 |
Lazy<T>(Func<T>, LazyThreadSafetyMode) |
初始化 Lazy<T> 类的新实例,它使用指定的初始化函数和线程安全模式。 |
Lazy<T>()
- Source:
- Lazy.cs
- Source:
- Lazy.cs
- Source:
- Lazy.cs
初始化 Lazy<T> 类的新实例。 发生迟缓初始化时,使用目标类型的无参数构造函数。
public:
Lazy();
public Lazy ();
Public Sub New ()
示例
下面的示例演示了此构造函数的用法。 它还说明了如何使用Lazy<T>(Boolean)为) 指定true
(构造函数 (Lazy<T>(LazyThreadSafetyMode)为 mode
) 指定LazyThreadSafetyMode.ExecutionAndPublication构造isThreadSafe
函数。 若要切换到其他构造函数,只需更改注释掉的构造函数。
此示例定义一个将由多个线程之一延迟初始化的 LargeObject
类。 此示例中的两个关键代码行是创建初始值设定项和实际初始化。 在 Main
方法的开头,该示例为 LargeObject
创建线程安全的延迟初始值:
lazyLargeObject = new Lazy<LargeObject>();
// The following lines show how to use other constructors to achieve exactly the
// same result as the previous line:
//lazyLargeObject = new Lazy<LargeObject>(true);
//lazyLargeObject = new Lazy<LargeObject>(LazyThreadSafetyMode.ExecutionAndPublication);
let lazyLargeObject = Lazy<LargeObject>()
// The following lines show how to use other constructors to achieve exactly the
// same result as the previous line:
// let lazyLargeObject = Lazy<LargeObject>(true)
// let lazyLargeObject = Lazy<LargeObject>(LazyThreadSafetyMode.ExecutionAndPublication)
lazyLargeObject = New Lazy(Of LargeObject)()
' The following lines show how to use other constructors to achieve exactly the
' same result as the previous line:
'lazyLargeObject = New Lazy(Of LargeObject)(True)
'lazyLargeObject = New Lazy(Of LargeObject)(LazyThreadSafetyMode.ExecutionAndPublication)
该示例创建并启动在 对象上阻塞的三个 ManualResetEvent 线程,以便该示例可以一次性释放所有线程。 ThreadProc
所有三个线程使用的 方法调用 Value 属性以获取 LargeObject
实例:
LargeObject large = lazyLargeObject.Value;
let large = lazyLargeObject.Value
Dim large As LargeObject = lazyLargeObject.Value
类 Lazy<T> 提供锁定,因此只允许一个线程创建 LargeObject
实例。 该示例演示其他线程都获取相同的实例。
注意
为简单起见,此示例使用 Lazy<T> 的全局实例,所有方法都是 static
(在 Visual Basic 中Shared
)。 使用延迟初始化没有要求。
using System;
using System.Threading;
class Program
{
static Lazy<LargeObject> lazyLargeObject = null;
static void Main()
{
// The lazy initializer is created here. LargeObject is not created until the
// ThreadProc method executes.
lazyLargeObject = new Lazy<LargeObject>();
// The following lines show how to use other constructors to achieve exactly the
// same result as the previous line:
//lazyLargeObject = new Lazy<LargeObject>(true);
//lazyLargeObject = new Lazy<LargeObject>(LazyThreadSafetyMode.ExecutionAndPublication);
Console.WriteLine(
"\r\nLargeObject is not created until you access the Value property of the lazy" +
"\r\ninitializer. Press Enter to create LargeObject.");
Console.ReadLine();
// Create and start 3 threads, passing the same blocking event to all of them.
ManualResetEvent startingGate = new ManualResetEvent(false);
Thread[] threads = { new Thread(ThreadProc), new Thread(ThreadProc), new Thread(ThreadProc) };
foreach (Thread t in threads)
{
t.Start(startingGate);
}
// Give all 3 threads time to start and wait, then release them all at once.
Thread.Sleep(100);
startingGate.Set();
// Wait for all 3 threads to finish. (The order doesn't matter.)
foreach (Thread t in threads)
{
t.Join();
}
Console.WriteLine("\r\nPress Enter to end the program");
Console.ReadLine();
}
static void ThreadProc(object state)
{
// Wait for the signal.
ManualResetEvent waitForStart = (ManualResetEvent) state;
waitForStart.WaitOne();
LargeObject large = lazyLargeObject.Value;
// The following line introduces an artificial delay to exaggerate the race condition.
Thread.Sleep(5);
// IMPORTANT: Lazy initialization is thread-safe, but it doesn't protect the
// object after creation. You must lock the object before accessing it,
// unless the type is thread safe. (LargeObject is not thread safe.)
lock(large)
{
large.Data[0] = Thread.CurrentThread.ManagedThreadId;
Console.WriteLine("Initialized by thread {0}; last used by thread {1}.",
large.InitializedBy, large.Data[0]);
}
}
}
class LargeObject
{
int initBy = 0;
public int InitializedBy { get { return initBy; } }
public LargeObject()
{
initBy = Thread.CurrentThread.ManagedThreadId;
Console.WriteLine("LargeObject was created on thread id {0}.", initBy);
}
public long[] Data = new long[100000000];
}
/* This example produces output similar to the following:
LargeObject is not created until you access the Value property of the lazy
initializer. Press Enter to create LargeObject.
LargeObject was created on thread id 4.
Initialized by thread 4; last used by thread 3.
Initialized by thread 4; last used by thread 4.
Initialized by thread 4; last used by thread 5.
Press Enter to end the program
*/
open System
open System.Threading
type LargeObject() =
let initBy = Thread.CurrentThread.ManagedThreadId
do
printfn $"LargeObject was created on thread id {initBy}."
member val Data = Array.zeroCreate<int64> 100000000 with get
member _.InitializedBy = initBy
// The lazy initializer is created here. LargeObject is not created until the
// ThreadProc method executes.
let lazyLargeObject = Lazy<LargeObject>()
// The following lines show how to use other constructors to achieve exactly the
// same result as the previous line:
// let lazyLargeObject = Lazy<LargeObject>(true)
// let lazyLargeObject = Lazy<LargeObject>(LazyThreadSafetyMode.ExecutionAndPublication)
let threadProc (state: obj) =
// Wait for the signal.
let waitForStart = state :?> ManualResetEvent
waitForStart.WaitOne() |> ignore
let large = lazyLargeObject.Value
// The following line introduces an artificial delay to exaggerate the race condition.
Thread.Sleep 5
// IMPORTANT: Lazy initialization is thread-safe, but it doesn't protect the
// object after creation. You must lock the object before accessing it,
// unless the type is thread safe. (LargeObject is not thread safe.)
lock large (fun () ->
large.Data[0] <- Thread.CurrentThread.ManagedThreadId
printfn $"Initialized by thread {large.InitializedBy} last used by thread {large.Data[0]}." )
printfn """
LargeObject is not created until you access the Value property of the lazy
initializer. Press Enter to create LargeObject."""
stdin.ReadLine() |> ignore
// Create and start 3 threads, passing the same blocking event to all of them.
let startingGate = new ManualResetEvent false
let threads = [| Thread(ParameterizedThreadStart threadProc); Thread(ParameterizedThreadStart threadProc); Thread(ParameterizedThreadStart threadProc) |]
for t in threads do
t.Start startingGate
// Give all 3 threads time to start and wait, then release them all at once.
Thread.Sleep 100
startingGate.Set() |> ignore
// Wait for all 3 threads to finish. (The order doesn't matter.)
for t in threads do
t.Join()
printfn "\nPress Enter to end the program"
stdin.ReadLine() |> ignore
// This example produces output similar to the following:
// LargeObject is not created until you access the Value property of the lazy
// initializer. Press Enter to create LargeObject.
//
// LargeObject was created on thread id 4.
// Initialized by thread 4 last used by thread 3.
// Initialized by thread 4 last used by thread 4.
// Initialized by thread 4 last used by thread 5.
//
// Press Enter to end the program
Imports System.Threading
Class Program
Private Shared lazyLargeObject As Lazy(Of LargeObject) = Nothing
Shared Sub Main()
' The lazy initializer is created here. LargeObject is not created until the
' ThreadProc method executes.
lazyLargeObject = New Lazy(Of LargeObject)()
' The following lines show how to use other constructors to achieve exactly the
' same result as the previous line:
'lazyLargeObject = New Lazy(Of LargeObject)(True)
'lazyLargeObject = New Lazy(Of LargeObject)(LazyThreadSafetyMode.ExecutionAndPublication)
Console.WriteLine( _
vbCrLf & "LargeObject is not created until you access the Value property of the lazy" _
& vbCrLf & "initializer. Press Enter to create LargeObject.")
Console.ReadLine()
' Create and start 3 threads, passing the same blocking event to all of them.
Dim startingGate As New ManualResetEvent(False)
Dim threads() As Thread = { New Thread(AddressOf ThreadProc),
New Thread(AddressOf ThreadProc), New Thread(AddressOf ThreadProc) }
For Each t As Thread In threads
t.Start(startingGate)
Next t
' Give all 3 threads time to start and wait, then release them all at once.
Thread.Sleep(100)
startingGate.Set()
' Wait for all 3 threads to finish. (The order doesn't matter.)
For Each t As Thread In threads
t.Join()
Next t
Console.WriteLine(vbCrLf & "Press Enter to end the program")
Console.ReadLine()
End Sub
Private Shared Sub ThreadProc(ByVal state As Object)
' Wait for the signal.
Dim waitForStart As ManualResetEvent = CType(state, ManualResetEvent)
waitForStart.WaitOne()
Dim large As LargeObject = lazyLargeObject.Value
' The following line introduces an artificial delay to exaggerate the race condition.
Thread.Sleep(5)
' IMPORTANT: Lazy initialization is thread-safe, but it doesn't protect the
' object after creation. You must lock the object before accessing it,
' unless the type is thread safe. (LargeObject is not thread safe.)
SyncLock large
large.Data(0) = Thread.CurrentThread.ManagedThreadId
Console.WriteLine("Initialized by thread {0}; last used by thread {1}.", _
large.InitializedBy, large.Data(0))
End SyncLock
End Sub
End Class
Class LargeObject
Private initBy As Integer = 0
Public ReadOnly Property InitializedBy() As Integer
Get
Return initBy
End Get
End Property
Public Sub New()
initBy = Thread.CurrentThread.ManagedThreadId
Console.WriteLine("LargeObject was created on thread id {0}.", initBy)
End Sub
Public Data(100000000) As Long
End Class
' This example produces output similar to the following:
'
'LargeObject is not created until you access the Value property of the lazy
'initializer. Press Enter to create LargeObject.
'
'LargeObject was created on thread id 3.
'Initialized by thread 3; last used by thread 5.
'Initialized by thread 3; last used by thread 4.
'Initialized by thread 3; last used by thread 3.
'
'Press Enter to end the program
注解
使用此构造函数创建的实例可以同时从多个线程使用。
使用此构造函数初始化的 Lazy<T> 实例的线程安全模式为 LazyThreadSafetyMode.ExecutionAndPublication。 线程安全模式描述多个线程尝试初始化 Lazy<T> 实例时的行为。
Lazy<T>使用此构造函数创建的实例不会缓存异常。 有关更多信息,请参见 Lazy<T> 类或 System.Threading.LazyThreadSafetyMode 枚举。
另请参阅
适用于
Lazy<T>(Boolean)
- Source:
- Lazy.cs
- Source:
- Lazy.cs
- Source:
- Lazy.cs
初始化 Lazy<T> 类的新实例。 发生迟缓初始化时,使用目标类型的无参数构造函数和指定的初始化模式。
public:
Lazy(bool isThreadSafe);
public Lazy (bool isThreadSafe);
new Lazy<'T> : bool -> Lazy<'T>
Public Sub New (isThreadSafe As Boolean)
参数
- isThreadSafe
- Boolean
若要使此实例可同时由多个线程使用,则为 true
;若要使实例一次只能由一个线程使用,则为 false
。
示例
以下示例演示了如何使用此构造函数创建一个非线程安全的延迟初始值设定项,用于对延迟初始化对象的所有访问都发生在同一线程上的情况。 它还演示了使用Lazy<T>(LazyThreadSafetyMode)构造函数 (为 mode
指定 LazyThreadSafetyMode.None 。 若要切换到其他构造函数,只需更改注释掉的构造函数。
备注
有关演示如何在多线程方案中使用此构造函数的代码, true
(指定 isThreadSafe
) ,请参阅构造函数的示例 Lazy<T>() 。
该示例定义了一个 LargeObject
将延迟初始化的类。 Main
在 方法中,该示例创建 一个 Lazy<T> 实例,然后暂停。 按 Enter 键时,该示例将访问 Value 实例的 Lazy<T> 属性,这会导致初始化发生。 类的 LargeObject
构造函数显示控制台消息。
备注
为简单起见,此示例使用 Lazy<T> 的全局实例,所有方法都是 static
(在 Visual Basic 中Shared
)。 使用延迟初始化没有要求。
using System;
using System.Threading;
class Program
{
static Lazy<LargeObject> lazyLargeObject = null;
static void Main()
{
// The lazy initializer is created here. LargeObject is not created until the
// ThreadProc method executes.
lazyLargeObject = new Lazy<LargeObject>(false);
// The following lines show how to use other constructors to achieve exactly the
// same result as the previous line:
//lazyLargeObject = new Lazy<LargeObject>(LazyThreadSafetyMode.None);
Console.WriteLine(
"\r\nLargeObject is not created until you access the Value property of the lazy" +
"\r\ninitializer. Press Enter to create LargeObject.");
Console.ReadLine();
LargeObject large = lazyLargeObject.Value;
large.Data[11] = 89;
Console.WriteLine("\r\nPress Enter to end the program");
Console.ReadLine();
}
}
class LargeObject
{
public LargeObject()
{
Console.WriteLine("LargeObject was created on thread id {0}.",
Thread.CurrentThread.ManagedThreadId);
}
public long[] Data = new long[100000000];
}
/* This example produces output similar to the following:
LargeObject is not created until you access the Value property of the lazy
initializer. Press Enter to create LargeObject.
LargeObject was created on thread id 1.
Press Enter to end the program
*/
open System
open System.Threading
type LargeObject () =
do
printfn $"LargeObject was created on thread id {Thread.CurrentThread.ManagedThreadId}."
member val Data = Array.zeroCreate<int64> 100000000 with get
// The lazy initializer is created here. LargeObject is not created until the
// ThreadProc method executes.
let lazyLargeObject = Lazy<LargeObject> false
// The following lines show how to use other constructors to achieve exactly the
// same result as the previous line:
// let lazyLargeObject = Lazy<LargeObject>(LazyThreadSafetyMode.None)
printfn """
LargeObject is not created until you access the Value property of the lazy
initializer. Press Enter to create LargeObject."""
stdin.ReadLine() |> ignore
let large = lazyLargeObject.Value
large.Data[11] <- 89
printfn "\nPress Enter to end the program"
stdin.ReadLine() |> ignore
// This example produces output similar to the following:
// LargeObject is not created until you access the Value property of the lazy
// initializer. Press Enter to create LargeObject.
//
// LargeObject was created on thread id 1.
//
// Press Enter to end the program
Imports System.Threading
Friend Class Program
Private Shared lazyLargeObject As Lazy(Of LargeObject) = Nothing
Shared Sub Main()
' The lazy initializer is created here. LargeObject is not created until the
' ThreadProc method executes.
lazyLargeObject = New Lazy(Of LargeObject)(False)
' The following lines show how to use other constructors to achieve exactly the
' same result as the previous line:
'lazyLargeObject = new Lazy<LargeObject>(LazyThreadSafetyMode.None);
Console.WriteLine( _
vbCrLf & "LargeObject is not created until you access the Value property of the lazy" _
& vbCrLf & "initializer. Press Enter to create LargeObject.")
Console.ReadLine()
Dim large As LargeObject = lazyLargeObject.Value
large.Data(11) = 89
Console.WriteLine(vbCrLf & "Press Enter to end the program")
Console.ReadLine()
End Sub
End Class
Friend Class LargeObject
Public Sub New()
Console.WriteLine("LargeObject was created on thread id {0}.", _
Thread.CurrentThread.ManagedThreadId)
End Sub
Public Data(100000000) As Long
End Class
' This example produces output similar to the following:
'
'LargeObject is not created until you access the Value property of the lazy
'initializer. Press Enter to create LargeObject.
'
'LargeObject was created on thread id 1.
'
'Press Enter to end the program
注解
如果 true
isThreadSafe
为 ,则使用此构造函数初始化的Lazy<T>实例的线程安全模式为 LazyThreadSafetyMode.ExecutionAndPublication ;否则,模式为 LazyThreadSafetyMode.None。 线程安全模式描述多个线程尝试初始化 Lazy<T> 实例时的行为。 若要指定 LazyThreadSafetyMode.PublicationOnly 模式,请使用 Lazy<T>(Func<T>, LazyThreadSafetyMode) 或 Lazy<T>(LazyThreadSafetyMode) 构造函数。
Lazy<T>使用此构造函数创建的实例不会缓存异常。 有关更多信息,请参见 Lazy<T> 类或 System.Threading.LazyThreadSafetyMode 枚举。
另请参阅
适用于
Lazy<T>(Func<T>)
- Source:
- Lazy.cs
- Source:
- Lazy.cs
- Source:
- Lazy.cs
初始化 Lazy<T> 类的新实例。 出现迟缓初始化时,将使用指定的初始化函数。
public:
Lazy(Func<T> ^ valueFactory);
public Lazy (Func<T> valueFactory);
new Lazy<'T> : Func<'T> -> Lazy<'T>
Public Sub New (valueFactory As Func(Of T))
参数
- valueFactory
- Func<T>
调用用于在需要时生成延迟初始化值的委托。
例外
valueFactory
为 null
。
示例
以下示例演示了如何使用此构造函数提供延迟初始化和异常缓存。 它还演示了如何使用Lazy<T>(Func<T>, Boolean)为) 指定isThreadSafe
true
(构造函数, (Lazy<T>(Func<T>, LazyThreadSafetyMode)为 mode
) 指定LazyThreadSafetyMode.ExecutionAndPublication构造函数。 若要切换到其他构造函数,只需更改注释掉的构造函数。
此示例定义一个将由多个线程之一延迟初始化的 LargeObject
类。 代码的三个关键部分演示了如何创建初始值设定项、实际初始化以及 类的 LargeObject
构造函数,后者演示了异常缓存。 在 Main
方法的开头,该示例为 LargeObject
创建线程安全的延迟初始值:
lazyLargeObject = new Lazy<LargeObject>(InitLargeObject);
// The following lines show how to use other constructors to achieve exactly the
// same result as the previous line:
//lazyLargeObject = new Lazy<LargeObject>(InitLargeObject, true);
//lazyLargeObject = new Lazy<LargeObject>(InitLargeObject, LazyThreadSafetyMode.ExecutionAndPublication);
let lazyLargeObject = Lazy<LargeObject> initLargeObject
// The following lines show how to use other constructors to achieve exactly the
// same result as the previous line:
// let lazyLargeObject = Lazy<LargeObject>(initLargeObject, true)
// let lazyLargeObject = Lazy<LargeObject>(initLargeObject, LazyThreadSafetyMode.ExecutionAndPublication)
lazyLargeObject = New Lazy(Of LargeObject)(AddressOf InitLargeObject)
' The following lines show how to use other constructors to achieve exactly the
' same result as the previous line:
'lazyLargeObject = New Lazy(Of LargeObject)(AddressOf InitLargeObject, True)
'lazyLargeObject = New Lazy(Of LargeObject)(AddressOf InitLargeObject, LazyThreadSafetyMode.ExecutionAndPublication)
该示例创建并启动三个线程。 ThreadProc
所有三个线程使用的 方法调用 Value 属性以获取 LargeObject
实例:
try
{
LargeObject large = lazyLargeObject.Value;
// IMPORTANT: Lazy initialization is thread-safe, but it doesn't protect the
// object after creation. You must lock the object before accessing it,
// unless the type is thread safe. (LargeObject is not thread safe.)
lock(large)
{
large.Data[0] = Thread.CurrentThread.ManagedThreadId;
Console.WriteLine("Initialized by thread {0}; last used by thread {1}.",
large.InitializedBy, large.Data[0]);
}
}
catch (ApplicationException aex)
{
Console.WriteLine("Exception: {0}", aex.Message);
}
try
let large = lazyLargeObject.Value
// IMPORTANT: Lazy initialization is thread-safe, but it doesn't protect the
// object after creation. You must lock the object before accessing it,
// unless the type is thread safe. (LargeObject is not thread safe.)
lock large (fun () ->
large.Data[0] <- Thread.CurrentThread.ManagedThreadId
printfn $"Initialized by thread {large.InitializedBy} last used by thread {large.Data[0]}.")
with :? ApplicationException as aex ->
printfn $"Exception: {aex.Message}"
Try
Dim large As LargeObject = lazyLargeObject.Value
' IMPORTANT: Lazy initialization is thread-safe, but it doesn't protect the
' object after creation. You must lock the object before accessing it,
' unless the type is thread safe. (LargeObject is not thread safe.)
SyncLock large
large.Data(0) = Thread.CurrentThread.ManagedThreadId
Console.WriteLine("Initialized by thread {0}; last used by thread {1}.", _
large.InitializedBy, large.Data(0))
End SyncLock
Catch aex As ApplicationException
Console.WriteLine("Exception: {0}", aex.Message)
End Try
在 类的 LargeObject
构造函数中,代码的第三个关键部分在第一 LargeObject
次创建实例时引发异常,但随后允许创建实例:
static int instanceCount = 0;
public LargeObject()
{
if (1 == Interlocked.Increment(ref instanceCount))
{
throw new ApplicationException("Throw only ONCE.");
}
initBy = Thread.CurrentThread.ManagedThreadId;
Console.WriteLine("LargeObject was created on thread id {0}.", initBy);
}
type LargeObject() =
static let mutable instanceCount = 0
let initBy = Thread.CurrentThread.ManagedThreadId
do
if 1 = Interlocked.Increment &instanceCount then
raise (ApplicationException "Throw only ONCE.")
printfn $"LargeObject was created on thread id {initBy}."
Private Shared instanceCount As Integer = 0
Public Sub New()
If 1 = Interlocked.Increment(instanceCount) Then
Throw New ApplicationException("Throw only ONCE.")
End If
initBy = Thread.CurrentThread.ManagedThreadId
Console.WriteLine("LargeObject was created on thread id {0}.", initBy)
End Sub
运行示例时,尝试创建 实例 LargeObject
的第一个线程失败,并捕获异常。 你可能期望下一个线程成功创建实例,但 Lazy<T> 对象已缓存异常。 因此,所有三个线程都会引发异常。
注意
为简单起见,此示例使用 Lazy<T> 的全局实例,所有方法都是 static
(在 Visual Basic 中Shared
)。 使用延迟初始化没有要求。
using System;
using System.Threading;
class Program
{
static Lazy<LargeObject> lazyLargeObject = null;
static LargeObject InitLargeObject()
{
return new LargeObject();
}
static void Main()
{
// The lazy initializer is created here. LargeObject is not created until the
// ThreadProc method executes.
lazyLargeObject = new Lazy<LargeObject>(InitLargeObject);
// The following lines show how to use other constructors to achieve exactly the
// same result as the previous line:
//lazyLargeObject = new Lazy<LargeObject>(InitLargeObject, true);
//lazyLargeObject = new Lazy<LargeObject>(InitLargeObject, LazyThreadSafetyMode.ExecutionAndPublication);
Console.WriteLine(
"\r\nLargeObject is not created until you access the Value property of the lazy" +
"\r\ninitializer. Press Enter to create LargeObject.");
Console.ReadLine();
// Create and start 3 threads, each of which tries to use LargeObject.
Thread[] threads = { new Thread(ThreadProc), new Thread(ThreadProc), new Thread(ThreadProc) };
foreach (Thread t in threads)
{
t.Start();
}
// Wait for all 3 threads to finish. (The order doesn't matter.)
foreach (Thread t in threads)
{
t.Join();
}
Console.WriteLine("\r\nPress Enter to end the program");
Console.ReadLine();
}
static void ThreadProc(object state)
{
try
{
LargeObject large = lazyLargeObject.Value;
// IMPORTANT: Lazy initialization is thread-safe, but it doesn't protect the
// object after creation. You must lock the object before accessing it,
// unless the type is thread safe. (LargeObject is not thread safe.)
lock(large)
{
large.Data[0] = Thread.CurrentThread.ManagedThreadId;
Console.WriteLine("Initialized by thread {0}; last used by thread {1}.",
large.InitializedBy, large.Data[0]);
}
}
catch (ApplicationException aex)
{
Console.WriteLine("Exception: {0}", aex.Message);
}
}
}
class LargeObject
{
int initBy = 0;
public int InitializedBy { get { return initBy; } }
static int instanceCount = 0;
public LargeObject()
{
if (1 == Interlocked.Increment(ref instanceCount))
{
throw new ApplicationException("Throw only ONCE.");
}
initBy = Thread.CurrentThread.ManagedThreadId;
Console.WriteLine("LargeObject was created on thread id {0}.", initBy);
}
public long[] Data = new long[100000000];
}
/* This example produces output similar to the following:
LargeObject is not created until you access the Value property of the lazy
initializer. Press Enter to create LargeObject.
Exception: Throw only ONCE.
Exception: Throw only ONCE.
Exception: Throw only ONCE.
Press Enter to end the program
*/
open System
open System.Threading
type LargeObject() =
static let mutable instanceCount = 0
let initBy = Thread.CurrentThread.ManagedThreadId
do
if 1 = Interlocked.Increment &instanceCount then
raise (ApplicationException "Throw only ONCE.")
printfn $"LargeObject was created on thread id {initBy}."
member _.InitializedBy = initBy
member val Data = Array.zeroCreate<int64> 100000000
let initLargeObject () =
LargeObject()
// The lazy initializer is created here. LargeObject is not created until the
// ThreadProc method executes.
let lazyLargeObject = Lazy<LargeObject> initLargeObject
// The following lines show how to use other constructors to achieve exactly the
// same result as the previous line:
// let lazyLargeObject = Lazy<LargeObject>(initLargeObject, true)
// let lazyLargeObject = Lazy<LargeObject>(initLargeObject, LazyThreadSafetyMode.ExecutionAndPublication)
let threadProc _ =
try
let large = lazyLargeObject.Value
// IMPORTANT: Lazy initialization is thread-safe, but it doesn't protect the
// object after creation. You must lock the object before accessing it,
// unless the type is thread safe. (LargeObject is not thread safe.)
lock large (fun () ->
large.Data[0] <- Thread.CurrentThread.ManagedThreadId
printfn $"Initialized by thread {large.InitializedBy} last used by thread {large.Data[0]}.")
with :? ApplicationException as aex ->
printfn $"Exception: {aex.Message}"
printfn """
LargeObject is not created until you access the Value property of the lazy
initializer. Press Enter to create LargeObject."""
stdin.ReadLine () |> ignore
// Create and start 3 threads, each of which tries to use LargeObject.
let threads =
[| Thread(ParameterizedThreadStart threadProc); Thread(ParameterizedThreadStart threadProc); Thread(ParameterizedThreadStart threadProc) |]
for t in threads do
t.Start()
// Wait for all 3 threads to finish. (The order doesn't matter.)
for t in threads do
t.Join()
printfn "\nPress Enter to end the program"
stdin.ReadLine() |> ignore
// This example produces output similar to the following:
// LargeObject is not created until you access the Value property of the lazy
// initializer. Press Enter to create LargeObject.
//
// Exception: Throw only ONCE.
// Exception: Throw only ONCE.
// Exception: Throw only ONCE.
//
// Press Enter to end the program
Imports System.Threading
Friend Class Program
Private Shared lazyLargeObject As Lazy(Of LargeObject) = Nothing
Private Shared Function InitLargeObject() As LargeObject
Return New LargeObject()
End Function
Shared Sub Main()
' The lazy initializer is created here. LargeObject is not created until the
' ThreadProc method executes.
lazyLargeObject = New Lazy(Of LargeObject)(AddressOf InitLargeObject)
' The following lines show how to use other constructors to achieve exactly the
' same result as the previous line:
'lazyLargeObject = New Lazy(Of LargeObject)(AddressOf InitLargeObject, True)
'lazyLargeObject = New Lazy(Of LargeObject)(AddressOf InitLargeObject, LazyThreadSafetyMode.ExecutionAndPublication)
Console.WriteLine(vbCrLf _
& "LargeObject is not created until you access the Value property of the lazy" _
& vbCrLf & "initializer. Press Enter to create LargeObject.")
Console.ReadLine()
' Create and start 3 threads, each of which tries to use LargeObject.
Dim threads() As Thread = { New Thread(AddressOf ThreadProc), _
New Thread(AddressOf ThreadProc), New Thread(AddressOf ThreadProc) }
For Each t As Thread In threads
t.Start()
Next t
' Wait for all 3 threads to finish. (The order doesn't matter.)
For Each t As Thread In threads
t.Join()
Next t
Console.WriteLine(vbCrLf & "Press Enter to end the program")
Console.ReadLine()
End Sub
Private Shared Sub ThreadProc(ByVal state As Object)
Try
Dim large As LargeObject = lazyLargeObject.Value
' IMPORTANT: Lazy initialization is thread-safe, but it doesn't protect the
' object after creation. You must lock the object before accessing it,
' unless the type is thread safe. (LargeObject is not thread safe.)
SyncLock large
large.Data(0) = Thread.CurrentThread.ManagedThreadId
Console.WriteLine("Initialized by thread {0}; last used by thread {1}.", _
large.InitializedBy, large.Data(0))
End SyncLock
Catch aex As ApplicationException
Console.WriteLine("Exception: {0}", aex.Message)
End Try
End Sub
End Class
Friend Class LargeObject
Private initBy As Integer = 0
Public ReadOnly Property InitializedBy() As Integer
Get
Return initBy
End Get
End Property
Private Shared instanceCount As Integer = 0
Public Sub New()
If 1 = Interlocked.Increment(instanceCount) Then
Throw New ApplicationException("Throw only ONCE.")
End If
initBy = Thread.CurrentThread.ManagedThreadId
Console.WriteLine("LargeObject was created on thread id {0}.", initBy)
End Sub
Public Data(99999999) As Long
End Class
' This example produces output similar to the following:
'
'LargeObject is not created until you access the Value property of the lazy
'initializer. Press Enter to create LargeObject.
'
'Exception: Throw only ONCE.
'Exception: Throw only ONCE.
'Exception: Throw only ONCE.
'
'Press Enter to end the program
'
注解
使用此构造函数创建的实例可以同时从多个线程使用。
使用此构造函数初始化的 Lazy<T> 实例的线程安全模式为 LazyThreadSafetyMode.ExecutionAndPublication。 线程安全模式描述多个线程尝试初始化 Lazy<T> 实例时的行为。
缓存 引发 valueFactory
的异常。 有关更多信息,请参见 Lazy<T> 类或 System.Threading.LazyThreadSafetyMode 枚举。
另请参阅
适用于
Lazy<T>(LazyThreadSafetyMode)
- Source:
- Lazy.cs
- Source:
- Lazy.cs
- Source:
- Lazy.cs
初始化 Lazy<T> 类的新实例,其中使用 T
的无参数构造函数和指定的线程安全性模式。
public:
Lazy(System::Threading::LazyThreadSafetyMode mode);
public Lazy (System.Threading.LazyThreadSafetyMode mode);
new Lazy<'T> : System.Threading.LazyThreadSafetyMode -> Lazy<'T>
Public Sub New (mode As LazyThreadSafetyMode)
参数
- mode
- LazyThreadSafetyMode
一个枚举值,用于指定线程安全模式。
例外
mode
包含无效值。
示例
以下示例演示了如何使用此构造函数创建延迟初始值设定项,使多个线程能够争用以延迟方式创建对象。 多个线程可能会成功创建实例,但所有线程都使用首先创建的实例。
注意
有关演示如何在单线程方案中使用此构造函数的示例, (LazyThreadSafetyMode.None 指定 mode
) ,请参阅 Lazy<T>(Boolean) 构造函数。 有关演示如何使用此构造函数在多线程方案中提供锁定而不是争用条件的示例, (指定 LazyThreadSafetyMode.ExecutionAndPublication) mode
,请参阅 Lazy<T>() 构造函数。
该示例定义了一个 LargeObject
类,该类将由多个线程中的任何一个延迟初始化。 代码的三个关键部分说明了如何创建初始值设定项、实际初始化以及 类的 LargeObject
构造函数和终结器。 在 方法的 Main
开头,该示例创建 Lazy<T> 对象,该对象执行 的延迟初始化 LargeObject
:
lazyLargeObject = new Lazy<LargeObject>(LazyThreadSafetyMode.PublicationOnly);
let lazyLargeObject = Lazy<LargeObject> LazyThreadSafetyMode.PublicationOnly
lazyLargeObject = New Lazy(Of LargeObject)(LazyThreadSafetyMode.PublicationOnly)
该示例创建并启动在 对象上阻止的三个 ManualResetEvent 线程,以便该示例可以一次性释放所有线程。 在 ThreadProc
由所有三个线程使用的方法中,调用 Value 属性将创建 LargeObject
实例:
LargeObject large = lazyLargeObject.Value;
let large = lazyLargeObject.Value
Dim large As LargeObject = lazyLargeObject.Value
由于 实例的 Lazy<T> 构造函数指定 LazyThreadSafetyMode.PublicationOnly了 ,因此允许所有三个线程创建 LargeObject
实例。 该示例通过在 构造函数和 类的终结器中显示控制台消息来演示这一 LargeObject
点:
public LargeObject()
{
initBy = Thread.CurrentThread.ManagedThreadId;
Console.WriteLine("Constructor: Instance initializing on thread {0}", initBy);
}
~LargeObject()
{
Console.WriteLine("Finalizer: Instance was initialized on {0}", initBy);
}
type LargeObject() =
let initBy = Thread.CurrentThread.ManagedThreadId
do
printfn $"Constructor: Instance initializing on thread {initBy}"
override _.Finalize() =
printfn $"Finalizer: Instance was initialized on {initBy}"
Public Sub New()
initBy = Thread.CurrentThread.ManagedThreadId
Console.WriteLine("Constructor: Instance initializing on thread {0}", initBy)
End Sub
Protected Overrides Sub Finalize()
Console.WriteLine("Finalizer: Instance was initialized on {0}", initBy)
End Sub
但是, Lazy<T> 对象可确保所有线程只使用一个实例。 该示例的输出显示所有三个线程都使用同一实例,还显示垃圾回收可以回收另外两个实例。
注意
为简单起见,此示例使用 Lazy<T> 的全局实例,所有方法都是 static
(在 Visual Basic 中Shared
)。 使用延迟初始化没有要求。
using System;
using System.Threading;
class Program
{
static Lazy<LargeObject> lazyLargeObject = null;
static void Main()
{
// The lazy initializer is created here. LargeObject is not created until the
// ThreadProc method executes.
lazyLargeObject = new Lazy<LargeObject>(LazyThreadSafetyMode.PublicationOnly);
// Create and start 3 threads, passing the same blocking event to all of them.
ManualResetEvent startingGate = new ManualResetEvent(false);
Thread[] threads = { new Thread(ThreadProc), new Thread(ThreadProc), new Thread(ThreadProc) };
foreach (Thread t in threads)
{
t.Start(startingGate);
}
// Give all 3 threads time to start and wait, then release them all at once.
Thread.Sleep(50);
startingGate.Set();
// Wait for all 3 threads to finish. (The order doesn't matter.)
foreach (Thread t in threads)
{
t.Join();
}
Console.WriteLine(
"\r\nThreads are complete. Running GC.Collect() to reclaim the extra instances.");
GC.Collect();
// Allow time for garbage collection, which happens asynchronously.
Thread.Sleep(100);
Console.WriteLine(
"\r\nNote that all three threads used the instance that was not collected.");
Console.WriteLine("Press Enter to end the program");
Console.ReadLine();
}
static void ThreadProc(object state)
{
// Wait for the signal.
ManualResetEvent waitForStart = (ManualResetEvent) state;
waitForStart.WaitOne();
LargeObject large = lazyLargeObject.Value;
// The following line introduces an artificial delay, to exaggerate the race
// condition.
Thread.Sleep(5);
// IMPORTANT: Lazy initialization is thread-safe, but it doesn't protect the
// object after creation. You must lock the object before accessing it,
// unless the type is thread safe. (LargeObject is not thread safe.)
lock(large)
{
large.Data[0] = Thread.CurrentThread.ManagedThreadId;
Console.WriteLine("LargeObject was initialized by thread {0}; last used by thread {1}.",
large.InitializedBy, large.Data[0]);
}
}
}
class LargeObject
{
int initBy = -1;
public int InitializedBy { get { return initBy; } }
public LargeObject()
{
initBy = Thread.CurrentThread.ManagedThreadId;
Console.WriteLine("Constructor: Instance initializing on thread {0}", initBy);
}
~LargeObject()
{
Console.WriteLine("Finalizer: Instance was initialized on {0}", initBy);
}
public long[] Data = new long[100000000];
}
/* This example produces output similar to the following:
Constructor: Instance initializing on thread 4
Constructor: Instance initializing on thread 3
Constructor: Instance initializing on thread 5
LargeObject was initialized by thread 4; last used by thread 4.
LargeObject was initialized by thread 4; last used by thread 5.
LargeObject was initialized by thread 4; last used by thread 3.
Threads are complete. Running GC.Collect() to reclaim the extra instances.
Finalizer: Instance was initialized on 3
Finalizer: Instance was initialized on 5
Note that all three threads used the instance that was not collected.
Press Enter to end the program
Instance finalizing; initialized on 4
*/
open System
open System.Threading
type LargeObject() =
let initBy = Thread.CurrentThread.ManagedThreadId
do
printfn $"Constructor: Instance initializing on thread {initBy}"
override _.Finalize() =
printfn $"Finalizer: Instance was initialized on {initBy}"
member _.InitializedBy = initBy
member val Data = Array.zeroCreate<int64> 100000000
// The lazy initializer is created here. LargeObject is not created until the
// ThreadProc method executes.
let lazyLargeObject = Lazy<LargeObject> LazyThreadSafetyMode.PublicationOnly
let threadProc (state: obj) =
// Wait for the signal.
let waitForStart = state :?> ManualResetEvent
waitForStart.WaitOne() |> ignore
let large = lazyLargeObject.Value
// The following line introduces an artificial delay, to exaggerate the race
// condition.
Thread.Sleep 5
// IMPORTANT: Lazy initialization is thread-safe, but it doesn't protect the
// object after creation. You must lock the object before accessing it,
// unless the type is thread safe. (LargeObject is not thread safe.)
lock large (fun () ->
large.Data[0] <- Thread.CurrentThread.ManagedThreadId
printfn $"LargeObject was initialized by thread {large.InitializedBy} last used by thread {large.Data[0]}.")
// Create and start 3 threads, passing the same blocking event to all of them.
let startingGate = new ManualResetEvent false
let threads =
[| Thread(ParameterizedThreadStart threadProc); Thread(ParameterizedThreadStart threadProc); Thread(ParameterizedThreadStart threadProc) |]
for t in threads do
t.Start startingGate
// Give all 3 threads time to start and wait, then release them all at once.
Thread.Sleep 50
startingGate.Set() |> ignore
// Wait for all 3 threads to finish. (The order doesn't matter.)
for t in threads do
t.Join()
printfn "\nThreads are complete. Running GC.Collect() to reclaim the extra instances."
GC.Collect()
// Allow time for garbage collection, which happens asynchronously.
Thread.Sleep 100
printfn "\nNote that all three threads used the instance that was not collected."
printfn "Press Enter to end the program"
stdin.ReadLine() |> ignore
// This example produces output similar to the following:
// Constructor: Instance initializing on thread 4
// Constructor: Instance initializing on thread 3
// Constructor: Instance initializing on thread 5
// LargeObject was initialized by thread 4 last used by thread 4.
// LargeObject was initialized by thread 4 last used by thread 5.
// LargeObject was initialized by thread 4 last used by thread 3.
//
// Threads are complete. Running GC.Collect() to reclaim the extra instances.
// Finalizer: Instance was initialized on 3
// Finalizer: Instance was initialized on 5
//
// Note that all three threads used the instance that was not collected.
// Press Enter to end the program
//
// Instance finalizing initialized on 4
Imports System.Threading
Friend Class Program
Private Shared lazyLargeObject As Lazy(Of LargeObject) = Nothing
Shared Sub Main()
' The lazy initializer is created here. LargeObject is not created until the
' ThreadProc method executes.
lazyLargeObject = New Lazy(Of LargeObject)(LazyThreadSafetyMode.PublicationOnly)
' Create and start 3 threads, passing the same blocking event to all of them.
Dim startingGate As New ManualResetEvent(False)
Dim threads() As Thread = { _
New Thread(AddressOf ThreadProc), _
New Thread(AddressOf ThreadProc), _
New Thread(AddressOf ThreadProc) _
}
For Each t As Thread In threads
t.Start(startingGate)
Next t
' Give all 3 threads time to start and wait, then release them all at once.
Thread.Sleep(50)
startingGate.Set()
' Wait for all 3 threads to finish. (The order doesn't matter.)
For Each t As Thread In threads
t.Join()
Next t
Console.WriteLine(vbCrLf & _
"Threads are complete. Running GC.Collect() to reclaim the extra instances.")
GC.Collect()
' Allow time for garbage collection, which happens asynchronously.
Thread.Sleep(100)
Console.WriteLine(vbCrLf & _
"Note that all three threads used the instance that was not collected.")
Console.WriteLine("Press Enter to end the program")
Console.ReadLine()
End Sub
Private Shared Sub ThreadProc(ByVal state As Object)
' Wait for the signal.
Dim waitForStart As ManualResetEvent = CType(state, ManualResetEvent)
waitForStart.WaitOne()
Dim large As LargeObject = lazyLargeObject.Value
' The following line introduces an artificial delay to exaggerate the race condition.
Thread.Sleep(5)
' IMPORTANT: Lazy initialization is thread-safe, but it doesn't protect the
' object after creation. You must lock the object before accessing it,
' unless the type is thread safe. (LargeObject is not thread safe.)
SyncLock large
large.Data(0) = Thread.CurrentThread.ManagedThreadId
Console.WriteLine( _
"LargeObject was initialized by thread {0}; last used by thread {1}.", _
large.InitializedBy, large.Data(0))
End SyncLock
End Sub
End Class
Friend Class LargeObject
Private initBy As Integer = -1
Public ReadOnly Property InitializedBy() As Integer
Get
Return initBy
End Get
End Property
Public Sub New()
initBy = Thread.CurrentThread.ManagedThreadId
Console.WriteLine("Constructor: Instance initializing on thread {0}", initBy)
End Sub
Protected Overrides Sub Finalize()
Console.WriteLine("Finalizer: Instance was initialized on {0}", initBy)
End Sub
Public Data(100000000) As Long
End Class
' This example produces output similar to the following:
'
'Constructor: Instance initializing on thread 3
'Constructor: Instance initializing on thread 5
'Constructor: Instance initializing on thread 4
'LargeObject was initialized by thread 3; last used by thread 4.
'LargeObject was initialized by thread 3; last used by thread 3.
'LargeObject was initialized by thread 3; last used by thread 5.
'
'Threads are complete. Running GC.Collect() to reclaim the extra instances.
'Finalizer: Instance was initialized on 5
'Finalizer: Instance was initialized on 4
'
'Note that all three threads used the instance that was not collected.
'Press Enter to end the program
'
'Finalizer: Instance was initialized on 3
'
注解
实例的 Lazy<T> 线程安全模式描述了多个线程尝试初始化实例 Lazy<T> 时的行为。
Lazy<T>使用此构造函数创建的实例不会缓存异常。 有关更多信息,请参见 Lazy<T> 类或 System.Threading.LazyThreadSafetyMode 枚举。
另请参阅
适用于
Lazy<T>(T)
Lazy<T>(Func<T>, Boolean)
- Source:
- Lazy.cs
- Source:
- Lazy.cs
- Source:
- Lazy.cs
初始化 Lazy<T> 类的新实例。 当延迟初始化发生时,将使用指定的初始化函数和初始化模式。
public:
Lazy(Func<T> ^ valueFactory, bool isThreadSafe);
public Lazy (Func<T> valueFactory, bool isThreadSafe);
new Lazy<'T> : Func<'T> * bool -> Lazy<'T>
Public Sub New (valueFactory As Func(Of T), isThreadSafe As Boolean)
参数
- valueFactory
- Func<T>
调用用于在需要时生成延迟初始化值的委托。
- isThreadSafe
- Boolean
若要使此实例可同时由多个线程使用,则为 true
;若要使此实例一次只能由一个线程使用,则为 false
。
例外
valueFactory
为 null
。
示例
以下示例演示了在单个线程的方案中,使用此构造函数提供延迟初始化和异常缓存。 它还演示了如何使用 Lazy<T> 为) 指定 LazyThreadSafetyMode.Nonemode
(构造函数。 若要切换到该构造函数,只需更改注释掉的构造函数。
注意
有关演示如何在多线程方案中使用此构造函数的代码 (指定 true
) isThreadSafe
,请参阅构造函数的示例 Lazy<T>(Func<T>) 。
此示例定义一个将由多个线程之一延迟初始化的 LargeObject
类。 代码的三个关键部分演示了初始值设定项的创建、实际初始化以及类的 LargeObject
构造函数,这些构造函数演示了异常缓存。 在 Main
方法的开头,该示例为 LargeObject
创建线程安全的延迟初始值:
lazyLargeObject = new Lazy<LargeObject>(InitLargeObject, false);
// The following lines show how to use other constructors to achieve exactly the
// same result as the previous line:
//lazyLargeObject = new Lazy<LargeObject>(InitLargeObject, LazyThreadSafetyMode.None);
let lazyLargeObject = Lazy<LargeObject>(initLargeObject, false)
// The following lines show how to use other constructors to achieve exactly the
// same result as the previous line:
// let lazyLargeObject = Lazy<LargeObject>(initLargeObject, LazyThreadSafetyMode.None)
lazyLargeObject = New Lazy(Of LargeObject)(AddressOf InitLargeObject, False)
' The following lines show how to use other constructors to achieve exactly the
' same result as the previous line:
'lazyLargeObject = New Lazy(Of LargeObject)(AddressOf InitLargeObject, LazyThreadSafetyMode.None)
在对 构造函数的调用中 isThreadSafe
, 参数为 false
,因此 Lazy<T> 不是线程安全的。 由于它不是线程安全的,因此该示例在同一线程上调用属性 Value 三次:
for (int i = 0; i < 3; i++)
{
try
{
LargeObject large = lazyLargeObject.Value;
large.Data[11] = 89;
}
catch (ApplicationException aex)
{
Console.WriteLine("Exception: {0}", aex.Message);
}
}
for _ = 0 to 2 do
try
let large = lazyLargeObject.Value
large.Data[11] <- 89
with :? ApplicationException as aex ->
printfn $"Exception: {aex.Message}"
For i As Integer = 0 To 2
Try
Dim large As LargeObject = lazyLargeObject.Value
large.Data(11) = 89
Catch aex As ApplicationException
Console.WriteLine("Exception: {0}", aex.Message)
End Try
Next i
在 类的 LargeObject
构造函数中,代码的第三个键部分在首次创建实例时 LargeObject
引发异常,但随后允许创建实例:
static bool pleaseThrow = true;
public LargeObject()
{
if (pleaseThrow)
{
pleaseThrow = false;
throw new ApplicationException("Throw only ONCE.");
}
Console.WriteLine("LargeObject was created on thread id {0}.",
Thread.CurrentThread.ManagedThreadId);
}
type LargeObject() =
static let mutable pleaseThrow = true
do
if pleaseThrow then
pleaseThrow <- false
raise (ApplicationException "Throw only ONCE.")
printfn $"LargeObject was created on thread id {Thread.CurrentThread.ManagedThreadId}."
Private Shared pleaseThrow As Boolean = True
Public Sub New()
If pleaseThrow Then
pleaseThrow = False
Throw New ApplicationException("Throw only ONCE.")
End If
Console.WriteLine("LargeObject was created on thread id {0}.", _
Thread.CurrentThread.ManagedThreadId)
End Sub
运行该示例时,创建 实例的第 LargeObject
一次尝试失败,并捕获异常。 你可能预计下一次尝试会成功,但 Lazy<T> 对象已缓存异常。 因此,所有三次尝试都会引发异常。
注意
为简单起见,此示例使用 Lazy<T> 的全局实例,所有方法都是 static
(在 Visual Basic 中Shared
)。 使用延迟初始化没有要求。
using System;
using System.Threading;
class Program
{
static Lazy<LargeObject> lazyLargeObject = null;
static LargeObject InitLargeObject()
{
return new LargeObject();
}
static void Main()
{
// The lazy initializer is created here. LargeObject is not created until the
// ThreadProc method executes.
lazyLargeObject = new Lazy<LargeObject>(InitLargeObject, false);
// The following lines show how to use other constructors to achieve exactly the
// same result as the previous line:
//lazyLargeObject = new Lazy<LargeObject>(InitLargeObject, LazyThreadSafetyMode.None);
Console.WriteLine(
"\r\nLargeObject is not created until you access the Value property of the lazy" +
"\r\ninitializer. Press Enter to create LargeObject (three tries).");
Console.ReadLine();
for (int i = 0; i < 3; i++)
{
try
{
LargeObject large = lazyLargeObject.Value;
large.Data[11] = 89;
}
catch (ApplicationException aex)
{
Console.WriteLine("Exception: {0}", aex.Message);
}
}
Console.WriteLine("\r\nPress Enter to end the program");
Console.ReadLine();
}
}
class LargeObject
{
static bool pleaseThrow = true;
public LargeObject()
{
if (pleaseThrow)
{
pleaseThrow = false;
throw new ApplicationException("Throw only ONCE.");
}
Console.WriteLine("LargeObject was created on thread id {0}.",
Thread.CurrentThread.ManagedThreadId);
}
public long[] Data = new long[100000000];
}
/* This example produces output similar to the following:
LargeObject is not created until you access the Value property of the lazy
initializer. Press Enter to create LargeObject (three tries).
Exception: Throw only ONCE.
Exception: Throw only ONCE.
Exception: Throw only ONCE.
Press Enter to end the program
*/
open System
open System.Threading
type LargeObject() =
static let mutable pleaseThrow = true
do
if pleaseThrow then
pleaseThrow <- false
raise (ApplicationException "Throw only ONCE.")
printfn $"LargeObject was created on thread id {Thread.CurrentThread.ManagedThreadId}."
member val Data = Array.zeroCreate<int64> 100000000
let initLargeObject () =
LargeObject()
// The lazy initializer is created here. LargeObject is not created until the
// ThreadProc method executes.
let lazyLargeObject = Lazy<LargeObject>(initLargeObject, false)
// The following lines show how to use other constructors to achieve exactly the
// same result as the previous line:
// let lazyLargeObject = Lazy<LargeObject>(initLargeObject, LazyThreadSafetyMode.None)
printfn """
LargeObject is not created until you access the Value property of the lazy
initializer. Press Enter to create LargeObject (three tries)."""
stdin.ReadLine() |> ignore
for _ = 0 to 2 do
try
let large = lazyLargeObject.Value
large.Data[11] <- 89
with :? ApplicationException as aex ->
printfn $"Exception: {aex.Message}"
printfn "\nPress Enter to end the program"
stdin.ReadLine() |> ignore
// This example produces output similar to the following:
// LargeObject is not created until you access the Value property of the lazy
// initializer. Press Enter to create LargeObject (three tries).
//
// Exception: Throw only ONCE.
// Exception: Throw only ONCE.
// Exception: Throw only ONCE.
//
// Press Enter to end the program
Imports System.Threading
Friend Class Program
Private Shared lazyLargeObject As Lazy(Of LargeObject) = Nothing
Private Shared Function InitLargeObject() As LargeObject
Return New LargeObject()
End Function
Shared Sub Main()
' The lazy initializer is created here. LargeObject is not created until the
' ThreadProc method executes.
lazyLargeObject = New Lazy(Of LargeObject)(AddressOf InitLargeObject, False)
' The following lines show how to use other constructors to achieve exactly the
' same result as the previous line:
'lazyLargeObject = New Lazy(Of LargeObject)(AddressOf InitLargeObject, LazyThreadSafetyMode.None)
Console.WriteLine(vbCrLf _
& "LargeObject is not created until you access the Value property of the lazy" _
& vbCrLf & "initializer. Press Enter to create LargeObject (three tries).")
Console.ReadLine()
For i As Integer = 0 To 2
Try
Dim large As LargeObject = lazyLargeObject.Value
large.Data(11) = 89
Catch aex As ApplicationException
Console.WriteLine("Exception: {0}", aex.Message)
End Try
Next i
Console.WriteLine(vbCrLf & "Press Enter to end the program")
Console.ReadLine()
End Sub
End Class
Friend Class LargeObject
Private Shared pleaseThrow As Boolean = True
Public Sub New()
If pleaseThrow Then
pleaseThrow = False
Throw New ApplicationException("Throw only ONCE.")
End If
Console.WriteLine("LargeObject was created on thread id {0}.", _
Thread.CurrentThread.ManagedThreadId)
End Sub
Public Data(100000000) As Long
End Class
' This example produces output similar to the following:
'
'LargeObject is not created until you access the Value property of the lazy
'initializer. Press Enter to create LargeObject (three tries).
'
'Exception: Throw only ONCE.
'Exception: Throw only ONCE.
'Exception: Throw only ONCE.
'
'Press Enter to end the program
'
注解
使用此构造函数初始化的 Lazy<T> 实例的线程安全模式为 LazyThreadSafetyMode.ExecutionAndPublication (如果 isThreadSafe
为 true
);否则,模式为 LazyThreadSafetyMode.None。 线程安全模式描述了多个线程尝试初始化 Lazy<T> 实例时的行为。
若要指定 LazyThreadSafetyMode.PublicationOnly 模式,请使用 Lazy<T>(Func<T>, LazyThreadSafetyMode) 或 Lazy<T>(LazyThreadSafetyMode) 构造函数。
将缓存 由 valueFactory
引发的异常。 有关更多信息,请参见 Lazy<T> 类或 System.Threading.LazyThreadSafetyMode 枚举。
另请参阅
适用于
Lazy<T>(Func<T>, LazyThreadSafetyMode)
- Source:
- Lazy.cs
- Source:
- Lazy.cs
- Source:
- Lazy.cs
初始化 Lazy<T> 类的新实例,它使用指定的初始化函数和线程安全模式。
public:
Lazy(Func<T> ^ valueFactory, System::Threading::LazyThreadSafetyMode mode);
public Lazy (Func<T> valueFactory, System.Threading.LazyThreadSafetyMode mode);
new Lazy<'T> : Func<'T> * System.Threading.LazyThreadSafetyMode -> Lazy<'T>
Public Sub New (valueFactory As Func(Of T), mode As LazyThreadSafetyMode)
参数
- valueFactory
- Func<T>
调用用于在需要时生成延迟初始化值的委托。
- mode
- LazyThreadSafetyMode
一个枚举值,用于指定线程安全模式。
例外
mode
包含无效值。
valueFactory
为 null
。
示例
以下示例演示了如何使用此构造函数创建延迟初始值设定项,该初始值设定项允许多个线程争用以延迟方式创建对象。 多个线程可能会成功创建实例,但所有线程都使用首先创建的实例。 此外,该示例演示了在指定 LazyThreadSafetyMode.PublicationOnly时永远不会缓存异常,即使初始化由函数而不是由延迟创建的类型的无参数构造函数执行。
备注
有关演示如何在 (指定 LazyThreadSafetyMode.Nonemode
) 的单线程方案中使用此构造函数的示例,请参阅 Lazy<T>(Boolean) 构造函数。 有关演示如何使用此构造函数在多线程方案中提供锁定而不是争用条件的示例, (指定 LazyThreadSafetyMode.ExecutionAndPublication) mode
,请参阅 Lazy<T>() 构造函数。
该示例定义了一个 LargeObject
类,该类将由多个线程中的任何一个延迟初始化。 代码的四个关键部分说明了如何创建初始值设定项、实际初始化、初始化函数以及 类的 LargeObject
构造函数和终结器。 在 方法的 Main
开头,该示例创建 Lazy<T> 执行延迟初始化的对象 LargeObject
:
lazyLargeObject = new Lazy<LargeObject>(InitLargeObject,
LazyThreadSafetyMode.PublicationOnly);
let lazyLargeObject = Lazy<LargeObject>(initLargeObject, LazyThreadSafetyMode.PublicationOnly)
lazyLargeObject = New Lazy(Of LargeObject)(AddressOf InitLargeObject, _
LazyThreadSafetyMode.PublicationOnly)
延迟初始值设定项使用 函数执行初始化。 在这种情况下,需要函数,因为类没有无参数构造函数 LargeObject
。
该示例创建并启动在 对象上阻止的三个 ManualResetEvent 线程,以便该示例可以一次性释放所有线程。 在 ThreadProc
由所有三个线程使用的方法中,调用 Value 属性将创建 LargeObject
实例:
LargeObject large = null;
try
{
large = lazyLargeObject.Value;
// The following line introduces an artificial delay to exaggerate the race condition.
Thread.Sleep(5);
// IMPORTANT: Lazy initialization is thread-safe, but it doesn't protect the
// object after creation. You must lock the object before accessing it,
// unless the type is thread safe. (LargeObject is not thread safe.)
lock(large)
{
large.Data[0] = Thread.CurrentThread.ManagedThreadId;
Console.WriteLine("LargeObject was initialized by thread {0}; last used by thread {1}.",
large.InitializedBy, large.Data[0]);
}
}
catch (ApplicationException ex)
{
Console.WriteLine("ApplicationException: {0}", ex.Message);
}
try
let large = lazyLargeObject.Value
// The following line introduces an artificial delay to exaggerate the race condition.
Thread.Sleep 5
// IMPORTANT: Lazy initialization is thread-safe, but it doesn't protect the
// object after creation. You must lock the object before accessing it,
// unless the type is thread safe. (LargeObject is not thread safe.)
lock large (fun () ->
large.Data[0] <- Thread.CurrentThread.ManagedThreadId
printfn $"LargeObject was initialized by thread {large.InitializedBy} last used by thread {large.Data[0]}.")
with :? ApplicationException as ex ->
printfn $"ApplicationException: {ex.Message}"
Dim large As LargeObject = Nothing
Try
large = lazyLargeObject.Value
' The following line introduces an artificial delay to exaggerate the race condition.
Thread.Sleep(5)
' IMPORTANT: Lazy initialization is thread-safe, but it doesn't protect the
' object after creation. You must lock the object before accessing it,
' unless the type is thread safe. (LargeObject is not thread safe.)
SyncLock large
large.Data(0) = Thread.CurrentThread.ManagedThreadId
Console.WriteLine( _
"LargeObject was initialized by thread {0}; last used by thread {1}.", _
large.InitializedBy, large.Data(0))
End SyncLock
Catch ex As ApplicationException
Console.WriteLine("ApplicationException: {0}", ex.Message)
End Try
在代码的第三个关键部分,调用延迟初始化函数来创建 LargeObject
实例。 函数在首次调用时会引发异常:
static int instanceCount = 0;
static LargeObject InitLargeObject()
{
if (1 == Interlocked.Increment(ref instanceCount))
{
throw new ApplicationException(
String.Format("Lazy initialization function failed on thread {0}.",
Thread.CurrentThread.ManagedThreadId));
}
return new LargeObject(Thread.CurrentThread.ManagedThreadId);
}
let mutable instanceCount = 0
let initLargeObject () =
if 1 = Interlocked.Increment &instanceCount then
raise (ApplicationException $"Lazy initialization function failed on thread {Thread.CurrentThread.ManagedThreadId}.")
LargeObject Thread.CurrentThread.ManagedThreadId
Private Shared instanceCount As Integer = 0
Private Shared Function InitLargeObject() As LargeObject
If 1 = Interlocked.Increment(instanceCount) Then
Throw New ApplicationException( _
"Lazy initialization function failed on thread " & _
Thread.CurrentThread.ManagedThreadId & ".")
End If
Return New LargeObject(Thread.CurrentThread.ManagedThreadId)
End Function
使用任何其他 LazyThreadSafetyMode 设置时,初始化函数中将缓存未经处理的异常。 但是, LazyThreadSafetyMode.PublicationOnly 禁止异常缓存。 该示例的输出演示了后续初始化对象的尝试成功。
注意
异常消息通常出现在指示其他线程已成功初始化对象的消息之后。 这是因为引发和捕获异常会导致延迟。
由于 实例的 Lazy<T> 构造函数指定 LazyThreadSafetyMode.PublicationOnly了 ,因此允许所有三个线程创建 LargeObject
实例。 该示例通过在 构造函数和 类的终结器中显示控制台消息来演示这一 LargeObject
点:
public LargeObject(int initializedBy)
{
initBy = initializedBy;
Console.WriteLine("Constructor: Instance initializing on thread {0}", initBy);
}
~LargeObject()
{
Console.WriteLine("Finalizer: Instance was initialized on {0}", initBy);
}
type LargeObject(initBy) =
do
printfn $"Constructor: Instance initializing on thread {initBy}"
override _.Finalize() =
printfn $"Finalizer: Instance was initialized on {initBy}"
Public Sub New(ByVal initializedBy As Integer)
initBy = initializedBy
Console.WriteLine("Constructor: Instance initializing on thread {0}", initBy)
End Sub
Protected Overrides Sub Finalize()
Console.WriteLine("Finalizer: Instance was initialized on {0}", initBy)
End Sub
对象 Lazy<T> 可确保除初始化函数引发异常) 线程之外, (的所有线程仅使用一个实例。 此示例的输出对此进行演示。
备注
为简单起见,此示例使用 Lazy<T> 的全局实例,所有方法都是 static
(在 Visual Basic 中Shared
)。 使用延迟初始化没有要求。
using System;
using System.Threading;
class Program
{
static Lazy<LargeObject> lazyLargeObject = null;
// Factory function for lazy initialization.
static int instanceCount = 0;
static LargeObject InitLargeObject()
{
if (1 == Interlocked.Increment(ref instanceCount))
{
throw new ApplicationException(
String.Format("Lazy initialization function failed on thread {0}.",
Thread.CurrentThread.ManagedThreadId));
}
return new LargeObject(Thread.CurrentThread.ManagedThreadId);
}
static void Main()
{
// The lazy initializer is created here. LargeObject is not created until the
// ThreadProc method executes.
lazyLargeObject = new Lazy<LargeObject>(InitLargeObject,
LazyThreadSafetyMode.PublicationOnly);
// Create and start 3 threads, passing the same blocking event to all of them.
ManualResetEvent startingGate = new ManualResetEvent(false);
Thread[] threads = { new Thread(ThreadProc), new Thread(ThreadProc), new Thread(ThreadProc) };
foreach (Thread t in threads)
{
t.Start(startingGate);
}
// Give all 3 threads time to start and wait, then release them all at once.
Thread.Sleep(50);
startingGate.Set();
// Wait for all 3 threads to finish. (The order doesn't matter.)
foreach (Thread t in threads)
{
t.Join();
}
Console.WriteLine(
"\r\nThreads are complete. Running GC.Collect() to reclaim extra instances.");
GC.Collect();
// Allow time for garbage collection, which happens asynchronously.
Thread.Sleep(100);
Console.WriteLine("\r\nNote that only one instance of LargeObject was used.");
Console.WriteLine("Press Enter to end the program");
Console.ReadLine();
}
static void ThreadProc(object state)
{
// Wait for the signal.
ManualResetEvent waitForStart = (ManualResetEvent) state;
waitForStart.WaitOne();
LargeObject large = null;
try
{
large = lazyLargeObject.Value;
// The following line introduces an artificial delay to exaggerate the race condition.
Thread.Sleep(5);
// IMPORTANT: Lazy initialization is thread-safe, but it doesn't protect the
// object after creation. You must lock the object before accessing it,
// unless the type is thread safe. (LargeObject is not thread safe.)
lock(large)
{
large.Data[0] = Thread.CurrentThread.ManagedThreadId;
Console.WriteLine("LargeObject was initialized by thread {0}; last used by thread {1}.",
large.InitializedBy, large.Data[0]);
}
}
catch (ApplicationException ex)
{
Console.WriteLine("ApplicationException: {0}", ex.Message);
}
}
}
class LargeObject
{
int initBy = -1;
public int InitializedBy { get { return initBy; } }
public LargeObject(int initializedBy)
{
initBy = initializedBy;
Console.WriteLine("Constructor: Instance initializing on thread {0}", initBy);
}
~LargeObject()
{
Console.WriteLine("Finalizer: Instance was initialized on {0}", initBy);
}
public long[] Data = new long[100000000];
}
/* This example produces output similar to the following:
Constructor: Instance initializing on thread 5
Constructor: Instance initializing on thread 4
ApplicationException: Lazy initialization function failed on thread 3.
LargeObject was initialized by thread 5; last used by thread 5.
LargeObject was initialized by thread 5; last used by thread 4.
Threads are complete. Running GC.Collect() to reclaim extra instances.
Finalizer: Instance was initialized on 4
Note that only one instance of LargeObject was used.
Press Enter to end the program
Finalizer: Instance was initialized on 5
*/
open System
open System.Threading
type LargeObject(initBy) =
do
printfn $"Constructor: Instance initializing on thread {initBy}"
override _.Finalize() =
printfn $"Finalizer: Instance was initialized on {initBy}"
member _.InitializedBy = initBy
member val Data = Array.zeroCreate<int64> 100000000 with get
// Factory function for lazy initialization.
let mutable instanceCount = 0
let initLargeObject () =
if 1 = Interlocked.Increment &instanceCount then
raise (ApplicationException $"Lazy initialization function failed on thread {Thread.CurrentThread.ManagedThreadId}.")
LargeObject Thread.CurrentThread.ManagedThreadId
// The lazy initializer is created here. LargeObject is not created until the
// ThreadProc method executes.
let lazyLargeObject = Lazy<LargeObject>(initLargeObject, LazyThreadSafetyMode.PublicationOnly)
let threadProc (state: obj) =
// Wait for the signal.
let waitForStart = state :?> ManualResetEvent
waitForStart.WaitOne() |> ignore
try
let large = lazyLargeObject.Value
// The following line introduces an artificial delay to exaggerate the race condition.
Thread.Sleep 5
// IMPORTANT: Lazy initialization is thread-safe, but it doesn't protect the
// object after creation. You must lock the object before accessing it,
// unless the type is thread safe. (LargeObject is not thread safe.)
lock large (fun () ->
large.Data[0] <- Thread.CurrentThread.ManagedThreadId
printfn $"LargeObject was initialized by thread {large.InitializedBy} last used by thread {large.Data[0]}.")
with :? ApplicationException as ex ->
printfn $"ApplicationException: {ex.Message}"
// Create and start 3 threads, passing the same blocking event to all of them.
let startingGate = new ManualResetEvent false
let threads =
[| Thread(ParameterizedThreadStart threadProc); Thread(ParameterizedThreadStart threadProc); Thread(ParameterizedThreadStart threadProc) |]
for t in threads do
t.Start startingGate
// Give all 3 threads time to start and wait, then release them all at once.
Thread.Sleep 50
startingGate.Set() |> ignore
// Wait for all 3 threads to finish. (The order doesn't matter.)
for t in threads do
t.Join()
printfn "\nThreads are complete. Running GC.Collect() to reclaim extra instances."
GC.Collect()
// Allow time for garbage collection, which happens asynchronously.
Thread.Sleep 100
printfn "\nNote that only one instance of LargeObject was used."
printfn "Press Enter to end the program"
stdin.ReadLine() |> ignore
// This example produces output similar to the following:
// Constructor: Instance initializing on thread 5
// Constructor: Instance initializing on thread 4
// ApplicationException: Lazy initialization function failed on thread 3.
// LargeObject was initialized by thread 5 last used by thread 5.
// LargeObject was initialized by thread 5 last used by thread 4.
//
// Threads are complete. Running GC.Collect() to reclaim extra instances.
// Finalizer: Instance was initialized on 4
//
// Note that only one instance of LargeObject was used.
// Press Enter to end the program
//
// Finalizer: Instance was initialized on 5
Imports System.Threading
Friend Class Program
Private Shared lazyLargeObject As Lazy(Of LargeObject) = Nothing
' Factory function for lazy initialization.
Private Shared instanceCount As Integer = 0
Private Shared Function InitLargeObject() As LargeObject
If 1 = Interlocked.Increment(instanceCount) Then
Throw New ApplicationException( _
"Lazy initialization function failed on thread " & _
Thread.CurrentThread.ManagedThreadId & ".")
End If
Return New LargeObject(Thread.CurrentThread.ManagedThreadId)
End Function
Shared Sub Main()
' The lazy initializer is created here. LargeObject is not created until the
' ThreadProc method executes.
lazyLargeObject = New Lazy(Of LargeObject)(AddressOf InitLargeObject, _
LazyThreadSafetyMode.PublicationOnly)
' Create and start 3 threads, passing the same blocking event to all of them.
Dim startingGate As New ManualResetEvent(False)
Dim threads() As Thread = { _
New Thread(AddressOf ThreadProc), _
New Thread(AddressOf ThreadProc), _
New Thread(AddressOf ThreadProc) _
}
For Each t As Thread In threads
t.Start(startingGate)
Next t
' Give all 3 threads time to start and wait, then release them all at once.
Thread.Sleep(50)
startingGate.Set()
' Wait for all 3 threads to finish. (The order doesn't matter.)
For Each t As Thread In threads
t.Join()
Next t
Console.WriteLine(vbCrLf & _
"Threads are complete. Running GC.Collect() to reclaim extra instances.")
GC.Collect()
' Allow time for garbage collection, which happens asynchronously.
Thread.Sleep(100)
Console.WriteLine(vbCrLf & "Note that only one instance of LargeObject was used.")
Console.WriteLine("Press Enter to end the program")
Console.ReadLine()
End Sub
Private Shared Sub ThreadProc(ByVal state As Object)
' Wait for the signal.
Dim waitForStart As ManualResetEvent = CType(state, ManualResetEvent)
waitForStart.WaitOne()
Dim large As LargeObject = Nothing
Try
large = lazyLargeObject.Value
' The following line introduces an artificial delay to exaggerate the race condition.
Thread.Sleep(5)
' IMPORTANT: Lazy initialization is thread-safe, but it doesn't protect the
' object after creation. You must lock the object before accessing it,
' unless the type is thread safe. (LargeObject is not thread safe.)
SyncLock large
large.Data(0) = Thread.CurrentThread.ManagedThreadId
Console.WriteLine( _
"LargeObject was initialized by thread {0}; last used by thread {1}.", _
large.InitializedBy, large.Data(0))
End SyncLock
Catch ex As ApplicationException
Console.WriteLine("ApplicationException: {0}", ex.Message)
End Try
End Sub
End Class
Friend Class LargeObject
Private initBy As Integer = -1
Public ReadOnly Property InitializedBy() As Integer
Get
Return initBy
End Get
End Property
Public Sub New(ByVal initializedBy As Integer)
initBy = initializedBy
Console.WriteLine("Constructor: Instance initializing on thread {0}", initBy)
End Sub
Protected Overrides Sub Finalize()
Console.WriteLine("Finalizer: Instance was initialized on {0}", initBy)
End Sub
Public Data(99999999) As Long
End Class
' This example produces output similar to the following:
'
'Constructor: Instance initializing on thread 4
'ApplicationException: Lazy initialization function failed on thread 3.
'Constructor: Instance initializing on thread 5
'LargeObject was initialized by thread 4; last used by thread 4.
'LargeObject was initialized by thread 4; last used by thread 5.
'
'Threads are complete. Running GC.Collect() to reclaim extra instances.
'Finalizer: Instance was initialized on 5
'
'Note that only one instance of LargeObject was used.
'Press Enter to end the program
'
'Finalizer: Instance was initialized on 4
'
注解
实例的 Lazy<T> 线程安全模式描述了多个线程尝试初始化实例 Lazy<T> 时的行为。
除非 为 ,否则mode
LazyThreadSafetyMode.PublicationOnly将缓存 由 valueFactory
引发的异常。 有关更多信息,请参见 Lazy<T> 类或 System.Threading.LazyThreadSafetyMode 枚举。
另请参阅
适用于
反馈
https://aka.ms/ContentUserFeedback。
即将发布:在整个 2024 年,我们将逐步淘汰作为内容反馈机制的“GitHub 问题”,并将其取代为新的反馈系统。 有关详细信息,请参阅:提交和查看相关反馈