Lazy<T> 构造函数

定义

初始化 Lazy<T> 类的新实例。

重载

Lazy<T>()

初始化 Lazy<T> 类的新实例。 发生延迟初始化时,将使用目标类型的无参数构造函数。

Lazy<T>(Boolean)

初始化 Lazy<T> 类的新实例。 发生延迟初始化时,将使用目标类型的无参数构造函数和指定的初始化模式。

Lazy<T>(Func<T>)

初始化 Lazy<T> 类的新实例。 发生延迟初始化时,将使用指定的初始化函数。

Lazy<T>(LazyThreadSafetyMode)

初始化 Lazy<T> 类的新实例,该实例使用 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) 构造函数(指定 isThreadSafetrue)和 Lazy<T>(LazyThreadSafetyMode) 构造函数(为 mode指定 LazyThreadSafetyMode.ExecutionAndPublication)。 若要切换到其他构造函数,只需更改注释掉哪些构造函数。

该示例定义一个 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) 构造函数(指定 LazyThreadSafetyMode.Nonemode。 若要切换到其他构造函数,只需更改注释掉哪个构造函数。

注意

有关演示如何在多线程方案中使用此构造函数的代码(为 isThreadSafe指定 true),请参阅 Lazy<T>() 构造函数的示例。

该示例定义一个 LargeObject 类,该类将延迟初始化。 在 Main 方法中,该示例创建 Lazy<T> 实例,然后暂停。 按 Enter 键时,该示例将访问 Lazy<T> 实例的 Value 属性,从而导致初始化。 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

注解

如果 isThreadSafetrue,则使用此构造函数初始化的 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) 构造函数(指定 isThreadSafetrue)和 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 包含无效值。

示例

以下示例演示如何使用此构造函数创建延迟初始值设定项,使多个线程能够争用以延迟方式创建对象。 多个线程可能会在创建实例时成功,但所有线程都使用首先创建的实例。

注意

有关演示如何在单线程方案中使用此构造函数的示例(为 mode指定 LazyThreadSafetyMode.None),请参阅 Lazy<T>(Boolean) 构造函数。 有关演示如何使用此构造函数在多线程方案中提供锁定而不是争用条件的示例(为 mode指定 LazyThreadSafetyMode.ExecutionAndPublication),请参阅 Lazy<T>() 构造函数。

该示例定义一个 LargeObject 类,该类将由多个线程中的任何一个延迟初始化。 代码的三个关键部分说明了如何创建初始值设定项、实际初始化以及 LargeObject 类的构造函数和终结器。 在 Main 方法的开头,该示例创建执行 LargeObject延迟初始化的 Lazy<T> 对象:

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

由于指定 LazyThreadSafetyMode.PublicationOnlyLazy<T> 实例的构造函数,因此允许所有三个线程创建 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)

Source:
Lazy.cs
Source:
Lazy.cs
Source:
Lazy.cs

初始化使用预初始化指定值的 Lazy<T> 类的新实例。

public:
 Lazy(T value);
public Lazy (T value);
new Lazy<'T> : 'T -> Lazy<'T>
Public Sub New (value As T)

参数

value
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> 构造函数(为 mode指定 LazyThreadSafetyMode.None)。 若要切换到该构造函数,只需更改注释掉哪个构造函数。

注意

有关演示如何在多线程方案中使用此构造函数的代码(为 isThreadSafe指定 true),请参阅 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
'

注解

如果 isThreadSafetrue,则使用此构造函数初始化的 Lazy<T> 实例的线程安全模式 LazyThreadSafetyMode.ExecutionAndPublication;否则,模式 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时永远不会缓存异常,即使初始化是由函数而不是延迟创建的类型的无参数构造函数执行的。

注意

有关演示如何在单线程方案中使用此构造函数的示例(为 mode指定 LazyThreadSafetyMode.None),请参阅 Lazy<T>(Boolean) 构造函数。 有关演示如何使用此构造函数在多线程方案中提供锁定而不是争用条件的示例(为 mode指定 LazyThreadSafetyMode.ExecutionAndPublication),请参阅 Lazy<T>() 构造函数。

该示例定义一个 LargeObject 类,该类将由多个线程中的任何一个延迟初始化。 代码的四个关键部分说明了如何创建初始值设定项、实际初始化、初始化函数以及 LargeObject 类的构造函数和终结器。 在 Main 方法的开头,该示例创建执行 LargeObject延迟初始化的 Lazy<T> 对象:

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 禁止异常缓存。 该示例的输出演示了后续尝试初始化对象成功。

注意

异常消息通常出现在指示其他线程已成功初始化对象的消息之后。 这是因为引发和捕获异常所引入的延迟。

由于指定 LazyThreadSafetyMode.PublicationOnlyLazy<T> 实例的构造函数,因此允许所有三个线程创建 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> 实例时的行为。

缓存由 valueFactory 引发的异常,除非 modeLazyThreadSafetyMode.PublicationOnly。 有关详细信息,请参阅 Lazy<T> 类或 System.Threading.LazyThreadSafetyMode 枚举。

另请参阅

适用于