Lazy<T> Konstruktoren

Definition

Initialisiert eine neue Instanz der Lazy<T> Klasse.

Überlädt

Lazy<T>()

Initialisiert eine neue Instanz der Lazy<T> Klasse. Wenn eine faule Initialisierung auftritt, wird der parameterlose Konstruktor des Zieltyps verwendet.

Lazy<T>(Boolean)

Initialisiert eine neue Instanz der Lazy<T> Klasse. Wenn die faule Initialisierung auftritt, werden der parameterlose Konstruktor des Zieltyps und der angegebene Initialisierungsmodus verwendet.

Lazy<T>(Func<T>)

Initialisiert eine neue Instanz der Lazy<T> Klasse. Wenn eine faule Initialisierung auftritt, wird die angegebene Initialisierungsfunktion verwendet.

Lazy<T>(LazyThreadSafetyMode)

Initialisiert eine neue Instanz der Lazy<T> Klasse, die den parameterlosen Konstruktor von T und den angegebenen Threadsicherheitsmodus verwendet.

Lazy<T>(T)

Initialisiert eine neue Instanz der Lazy<T> Klasse, die einen präinitialisierten angegebenen Wert verwendet.

Lazy<T>(Func<T>, Boolean)

Initialisiert eine neue Instanz der Lazy<T> Klasse. Wenn eine faule Initialisierung auftritt, werden die angegebene Initialisierungsfunktion und der Initialisierungsmodus verwendet.

Lazy<T>(Func<T>, LazyThreadSafetyMode)

Initialisiert eine neue Instanz der Lazy<T> Klasse, die die angegebene Initialisierungsfunktion und den Threadsicherheitsmodus verwendet.

Lazy<T>()

Quelle:
Lazy.cs
Quelle:
Lazy.cs
Quelle:
Lazy.cs

Initialisiert eine neue Instanz der Lazy<T> Klasse. Wenn eine faule Initialisierung auftritt, wird der parameterlose Konstruktor des Zieltyps verwendet.

public:
 Lazy();
public Lazy ();
Public Sub New ()

Beispiele

Im folgenden Beispiel wird die Verwendung dieses Konstruktors veranschaulicht. Außerdem wird die Verwendung des Lazy<T>(Boolean)-Konstruktors (angeben true für isThreadSafe) und des Lazy<T>(LazyThreadSafetyMode)-Konstruktors (angeben LazyThreadSafetyMode.ExecutionAndPublication für mode) veranschaulicht. Wenn Sie zu einem anderen Konstruktor wechseln möchten, ändern Sie einfach, welche Konstruktoren auskommentiert sind.

Im Beispiel wird eine LargeObject Klasse definiert, die durch einen von mehreren Threads lazily initialisiert wird. Die beiden Codezeilen in diesem Beispiel sind die Erstellung des Initialisierungsprogramms und der tatsächlichen Initialisierung. Am Anfang der Main-Methode erstellt das Beispiel den threadsicheren Lazy Initializer für 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)

Das Beispiel erstellt und startet drei Threads, die für ein ManualResetEvent -Objekt blockieren, damit das Beispiel die Threads auf einmal freigeben kann. Die ThreadProc Methode, die von allen drei Threads verwendet wird, ruft die Value-Eigenschaft auf, um die LargeObject Instanz abzurufen:

LargeObject large = lazyLargeObject.Value;
let large = lazyLargeObject.Value
Dim large As LargeObject = lazyLargeObject.Value

Die Lazy<T>-Klasse stellt eine Sperrung bereit, sodass nur ein Thread die LargeObject Instanz erstellen darf. Das Beispiel zeigt, dass die anderen Threads alle dieselbe Instanz erhalten.

Anmerkung

Aus Gründen der Einfachheit wird in diesem Beispiel eine globale Instanz von Lazy<T>verwendet, und alle Methoden sind static (Shared in Visual Basic). Dies sind keine Anforderungen für die Verwendung der faulen Initialisierung.

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

Hinweise

Eine Instanz, die mit diesem Konstruktor erstellt wird, kann gleichzeitig aus mehreren Threads verwendet werden.

Der Threadsicherheitsmodus einer Lazy<T> Instanz, die mit diesem Konstruktor initialisiert wird, ist LazyThreadSafetyMode.ExecutionAndPublication. Der Threadsicherheitsmodus beschreibt das Verhalten, wenn mehrere Threads versuchen, die Lazy<T> Instanz zu initialisieren.

Eine Lazy<T> Instanz, die mit diesem Konstruktor erstellt wird, speichert keine Ausnahmen zwischen. Weitere Informationen finden Sie in der Lazy<T> Klasse oder in der System.Threading.LazyThreadSafetyMode Enumeration.

Weitere Informationen

Gilt für:

Lazy<T>(Boolean)

Quelle:
Lazy.cs
Quelle:
Lazy.cs
Quelle:
Lazy.cs

Initialisiert eine neue Instanz der Lazy<T> Klasse. Wenn die faule Initialisierung auftritt, werden der parameterlose Konstruktor des Zieltyps und der angegebene Initialisierungsmodus verwendet.

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

Parameter

isThreadSafe
Boolean

true, damit diese Instanz gleichzeitig von mehreren Threads verwendet werden kann; false, damit die Instanz jeweils nur von einem Thread verwendet werden kann.

Beispiele

Das folgende Beispiel veranschaulicht die Verwendung dieses Konstruktors zum Erstellen eines faulen Initialisierungsprogramms, das nicht threadsicher ist, für Szenarien, in denen der gesamte Zugriff auf das lazily initialisierte Objekt im selben Thread erfolgt. Außerdem wird die Verwendung des Lazy<T>(LazyThreadSafetyMode)-Konstruktors veranschaulicht (angeben, LazyThreadSafetyMode.None für modeangegeben wird. Wenn Sie zu einem anderen Konstruktor wechseln möchten, ändern Sie einfach, welcher Konstruktor auskommentiert ist.

Anmerkung

Code, der die Verwendung dieses Konstruktors in Multithread-Szenarien veranschaulicht (Angeben von true für isThreadSafe), finden Sie im Beispiel für den Lazy<T>()-Konstruktor.

Im Beispiel wird eine LargeObject Klasse definiert, die lazily initialisiert wird. In der Main-Methode erstellt das Beispiel eine Lazy<T> Instanz und hält dann an. Wenn Sie die EINGABETASTE Drücken, greift das Beispiel auf die Value-Eigenschaft der Lazy<T> Instanz zu, wodurch initialisiert wird. Der Konstruktor der LargeObject Klasse zeigt eine Konsolenmeldung an.

Anmerkung

Aus Gründen der Einfachheit wird in diesem Beispiel eine globale Instanz von Lazy<T>verwendet, und alle Methoden sind static (Shared in Visual Basic). Dies sind keine Anforderungen für die Verwendung der faulen Initialisierung.

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

Hinweise

Der Threadsicherheitsmodus einer Lazy<T> Instanz, die mit diesem Konstruktor initialisiert wird, wird LazyThreadSafetyMode.ExecutionAndPublication, wenn isThreadSafetrueist; andernfalls ist der Modus LazyThreadSafetyMode.None. Der Threadsicherheitsmodus beschreibt das Verhalten, wenn mehrere Threads versuchen, die Lazy<T> Instanz zu initialisieren. Verwenden Sie zum Angeben des LazyThreadSafetyMode.PublicationOnly-Modus den Lazy<T>(Func<T>, LazyThreadSafetyMode)- oder Lazy<T>(LazyThreadSafetyMode)-Konstruktor.

Eine Lazy<T> Instanz, die mit diesem Konstruktor erstellt wird, speichert keine Ausnahmen zwischen. Weitere Informationen finden Sie in der Lazy<T> Klasse oder in der System.Threading.LazyThreadSafetyMode Enumeration.

Weitere Informationen

Gilt für:

Lazy<T>(Func<T>)

Quelle:
Lazy.cs
Quelle:
Lazy.cs
Quelle:
Lazy.cs

Initialisiert eine neue Instanz der Lazy<T> Klasse. Wenn eine faule Initialisierung auftritt, wird die angegebene Initialisierungsfunktion verwendet.

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))

Parameter

valueFactory
Func<T>

Der Delegat, der aufgerufen wird, um den lazily initialisierten Wert zu erzeugen, wenn er benötigt wird.

Ausnahmen

valueFactory ist null.

Beispiele

Im folgenden Beispiel wird die Verwendung dieses Konstruktors veranschaulicht, um eine faule Initialisierung mit Ausnahmezwischenspeicherung bereitzustellen. Außerdem wird die Verwendung des Lazy<T>(Func<T>, Boolean)-Konstruktors (angeben true für isThreadSafe) und des Lazy<T>(Func<T>, LazyThreadSafetyMode)-Konstruktors (angeben LazyThreadSafetyMode.ExecutionAndPublication für mode) veranschaulicht. Wenn Sie zu einem anderen Konstruktor wechseln möchten, ändern Sie einfach, welche Konstruktoren auskommentiert sind.

Im Beispiel wird eine LargeObject Klasse definiert, die durch einen von mehreren Threads lazily initialisiert wird. Die drei wichtigsten Codeabschnitte veranschaulichen die Erstellung des Initialisierungsprogramms, die tatsächliche Initialisierung und den Konstruktor der LargeObject-Klasse, die das Zwischenspeichern von Ausnahmen veranschaulicht. Am Anfang der Main-Methode erstellt das Beispiel den threadsicheren Lazy Initializer für 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)

Im Beispiel werden drei Threads erstellt und gestartet. Die ThreadProc Methode, die von allen drei Threads verwendet wird, ruft die Value-Eigenschaft auf, um die LargeObject Instanz abzurufen:

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

Im Konstruktor der LargeObject-Klasse löst der dritte Schlüsselabschnitt des Codes eine Ausnahme aus, wenn eine LargeObject Instanz zum ersten Mal erstellt wird. Anschließend kann jedoch die Instanzerstellung erfolgen:

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

Wenn das Beispiel ausgeführt wird, schlägt der erste Thread, der versucht, eine Instanz von LargeObject zu erstellen, fehl, und die Ausnahme wird abgefangen. Möglicherweise erwarten Sie, dass der nächste Thread erfolgreich eine Instanz erstellt hat, das Lazy<T>-Objekt die Ausnahme jedoch zwischengespeichert hat. Aus diesem Gründen lösen alle drei Threads die Ausnahme aus.

Anmerkung

Aus Gründen der Einfachheit wird in diesem Beispiel eine globale Instanz von Lazy<T>verwendet, und alle Methoden sind static (Shared in Visual Basic). Dies sind keine Anforderungen für die Verwendung der faulen Initialisierung.

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
'

Hinweise

Eine Instanz, die mit diesem Konstruktor erstellt wird, kann gleichzeitig aus mehreren Threads verwendet werden.

Der Threadsicherheitsmodus einer Lazy<T> Instanz, die mit diesem Konstruktor initialisiert wird, ist LazyThreadSafetyMode.ExecutionAndPublication. Der Threadsicherheitsmodus beschreibt das Verhalten, wenn mehrere Threads versuchen, die Lazy<T> Instanz zu initialisieren.

Ausnahmen, die von valueFactory ausgelöst werden, werden zwischengespeichert. Weitere Informationen finden Sie in der Lazy<T> Klasse oder in der System.Threading.LazyThreadSafetyMode Enumeration.

Weitere Informationen

Gilt für:

Lazy<T>(LazyThreadSafetyMode)

Quelle:
Lazy.cs
Quelle:
Lazy.cs
Quelle:
Lazy.cs

Initialisiert eine neue Instanz der Lazy<T> Klasse, die den parameterlosen Konstruktor von T und den angegebenen Threadsicherheitsmodus verwendet.

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)

Parameter

mode
LazyThreadSafetyMode

Einer der Enumerationswerte, die den Threadsicherheitsmodus angibt.

Ausnahmen

mode enthält einen ungültigen Wert.

Beispiele

Im folgenden Beispiel wird die Verwendung dieses Konstruktors veranschaulicht, um einen faulen Initialisierer zu erstellen, der es mehreren Threads ermöglicht, ein Objekt lazily zu erstellen. Mehrere Threads können beim Erstellen von Instanzen erfolgreich sein, aber alle Threads verwenden zuerst die Instanz, die erstellt wurde.

Anmerkung

Ein Beispiel, das veranschaulicht, wie dieser Konstruktor in Singlethread-Szenarien (angeben LazyThreadSafetyMode.None für mode) verwendet wird, finden Sie im Lazy<T>(Boolean)-Konstruktor. Ein Beispiel, das veranschaulicht, wie Sie diesen Konstruktor verwenden können, um Sperre anstelle von Racebedingungen in Multithread-Szenarien bereitzustellen (angeben LazyThreadSafetyMode.ExecutionAndPublication für mode), finden Sie im Lazy<T>()-Konstruktor.

Im Beispiel wird eine LargeObject Klasse definiert, die von mehreren Threads lazily initialisiert wird. Die drei wichtigsten Codeabschnitte veranschaulichen die Erstellung des Initialisierungsprogramms, die tatsächliche Initialisierung und den Konstruktor und Finalizer der LargeObject-Klasse. Am Anfang der Main-Methode erstellt das Beispiel das Lazy<T>-Objekt, das eine faule Initialisierung der LargeObjectdurchführt:

lazyLargeObject = new Lazy<LargeObject>(LazyThreadSafetyMode.PublicationOnly);
let lazyLargeObject = Lazy<LargeObject> LazyThreadSafetyMode.PublicationOnly
lazyLargeObject = New Lazy(Of LargeObject)(LazyThreadSafetyMode.PublicationOnly)

Das Beispiel erstellt und startet drei Threads, die für ein ManualResetEvent -Objekt blockieren, damit das Beispiel die Threads auf einmal freigeben kann. In der ThreadProc-Methode, die von allen drei Threads verwendet wird, erstellt das Aufrufen der Value-Eigenschaft die LargeObject Instanz:

LargeObject large = lazyLargeObject.Value;
let large = lazyLargeObject.Value
Dim large As LargeObject = lazyLargeObject.Value

Da der Konstruktor für die Lazy<T> Instanz LazyThreadSafetyMode.PublicationOnlyangegeben wurde, dürfen alle drei Threads LargeObject Instanzen erstellen. Im Beispiel wird dies veranschaulicht, indem Konsolenmeldungen im Konstruktor und im Finalizer der LargeObject-Klasse angezeigt werden:

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

Das Lazy<T>-Objekt stellt jedoch sicher, dass nur eine Instanz von allen Threads verwendet wird. Die Ausgabe aus dem Beispiel zeigt, dass alle drei Threads dieselbe Instanz verwenden, und zeigt auch, dass die anderen beiden Instanzen von der Garbage Collection zurückgefordert werden können.

Anmerkung

Aus Gründen der Einfachheit wird in diesem Beispiel eine globale Instanz von Lazy<T>verwendet, und alle Methoden sind static (Shared in Visual Basic). Dies sind keine Anforderungen für die Verwendung der faulen Initialisierung.

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
'

Hinweise

Der Threadsicherheitsmodus einer Lazy<T> Instanz beschreibt das Verhalten, wenn mehrere Threads versuchen, die Lazy<T> Instanz zu initialisieren.

Eine Lazy<T> Instanz, die mit diesem Konstruktor erstellt wird, speichert keine Ausnahmen zwischen. Weitere Informationen finden Sie in der Lazy<T> Klasse oder in der System.Threading.LazyThreadSafetyMode Enumeration.

Weitere Informationen

Gilt für:

Lazy<T>(T)

Quelle:
Lazy.cs
Quelle:
Lazy.cs
Quelle:
Lazy.cs

Initialisiert eine neue Instanz der Lazy<T> Klasse, die einen präinitialisierten angegebenen Wert verwendet.

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

Parameter

value
T

Der zu verwendende präinitialisierte Wert.

Hinweise

Eine mit diesem Konstruktor erstellte Instanz kann gleichzeitig von mehreren Threads verwendet werden.

Gilt für:

Lazy<T>(Func<T>, Boolean)

Quelle:
Lazy.cs
Quelle:
Lazy.cs
Quelle:
Lazy.cs

Initialisiert eine neue Instanz der Lazy<T> Klasse. Wenn eine faule Initialisierung auftritt, werden die angegebene Initialisierungsfunktion und der Initialisierungsmodus verwendet.

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)

Parameter

valueFactory
Func<T>

Der Delegat, der aufgerufen wird, um den lazily initialisierten Wert zu erzeugen, wenn er benötigt wird.

isThreadSafe
Boolean

true, damit diese Instanz gleichzeitig von mehreren Threads verwendet werden kann; false, damit diese Instanz jeweils nur von einem Thread verwendet werden kann.

Ausnahmen

valueFactory ist null.

Beispiele

Im folgenden Beispiel wird die Verwendung dieses Konstruktors veranschaulicht, um eine faule Initialisierung mit Ausnahmezwischenspeicherung in einem Szenario mit einem einzelnen Thread bereitzustellen. Außerdem wird die Verwendung des Lazy<T>-Konstruktors veranschaulicht (angeben LazyThreadSafetyMode.None für mode). Wenn Sie zu diesem Konstruktor wechseln möchten, ändern Sie einfach, welcher Konstruktor auskommentiert ist.

Anmerkung

Code, der die Verwendung dieses Konstruktors in Multithread-Szenarien veranschaulicht (Angeben von true für isThreadSafe), finden Sie im Beispiel für den Lazy<T>(Func<T>)-Konstruktor.

Im Beispiel wird eine LargeObject Klasse definiert, die durch einen von mehreren Threads lazily initialisiert wird. Die drei wichtigsten Codeabschnitte veranschaulichen die Erstellung des Initialisierungsprogramms, die tatsächliche Initialisierung und den Konstruktor der LargeObject-Klasse, die das Zwischenspeichern von Ausnahmen veranschaulicht. Am Anfang der Main-Methode erstellt das Beispiel den threadsicheren Lazy Initializer für 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)

Im Aufruf des Konstruktors ist der isThreadSafe Parameter false, sodass die Lazy<T> nicht threadsicher ist. Da es sich nicht um threadsicher handelt, ruft das Beispiel die eigenschaft Value dreimal im selben Thread auf:

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

Im Konstruktor der LargeObject-Klasse löst der dritte Schlüsselabschnitt des Codes eine Ausnahme aus, wenn eine LargeObject Instanz zum ersten Mal erstellt wird. Anschließend kann jedoch die Instanzerstellung erfolgen:

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

Wenn das Beispiel ausgeführt wird, schlägt der erste Versuch, eine Instanz von LargeObject fehl, und die Ausnahme wird abgefangen. Möglicherweise erwarten Sie, dass der nächste Versuch erfolgreich war, aber das Lazy<T>-Objekt die Ausnahme zwischengespeichert hat. Aus diesem Gründen lösen alle drei Versuche die Ausnahme aus.

Anmerkung

Aus Gründen der Einfachheit wird in diesem Beispiel eine globale Instanz von Lazy<T>verwendet, und alle Methoden sind static (Shared in Visual Basic). Dies sind keine Anforderungen für die Verwendung der faulen Initialisierung.

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
'

Hinweise

Der Threadsicherheitsmodus einer Lazy<T> Instanz, die mit diesem Konstruktor initialisiert wird, wird LazyThreadSafetyMode.ExecutionAndPublication, wenn isThreadSafetrueist; andernfalls ist der Modus LazyThreadSafetyMode.None. Der Threadsicherheitsmodus beschreibt das Verhalten, wenn mehrere Threads versuchen, die Lazy<T> Instanz zu initialisieren.

Verwenden Sie zum Angeben des LazyThreadSafetyMode.PublicationOnly-Modus den Lazy<T>(Func<T>, LazyThreadSafetyMode)- oder Lazy<T>(LazyThreadSafetyMode)-Konstruktor.

Ausnahmen, die von valueFactory ausgelöst werden, werden zwischengespeichert. Weitere Informationen finden Sie in der Lazy<T> Klasse oder in der System.Threading.LazyThreadSafetyMode Enumeration.

Weitere Informationen

Gilt für:

Lazy<T>(Func<T>, LazyThreadSafetyMode)

Quelle:
Lazy.cs
Quelle:
Lazy.cs
Quelle:
Lazy.cs

Initialisiert eine neue Instanz der Lazy<T> Klasse, die die angegebene Initialisierungsfunktion und den Threadsicherheitsmodus verwendet.

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)

Parameter

valueFactory
Func<T>

Der Delegat, der aufgerufen wird, um den lazily initialisierten Wert zu erzeugen, wenn er benötigt wird.

mode
LazyThreadSafetyMode

Einer der Enumerationswerte, die den Threadsicherheitsmodus angibt.

Ausnahmen

mode enthält einen ungültigen Wert.

valueFactory ist null.

Beispiele

Im folgenden Beispiel wird die Verwendung dieses Konstruktors veranschaulicht, um einen faulen Initialisierer zu erstellen, der es mehreren Threads ermöglicht, ein Objekt lazily zu erstellen. Mehrere Threads können beim Erstellen von Instanzen erfolgreich sein, aber alle Threads verwenden zuerst die Instanz, die erstellt wurde. Darüber hinaus veranschaulicht das Beispiel, dass Ausnahmen nie zwischengespeichert werden, wenn Sie LazyThreadSafetyMode.PublicationOnlyangeben, auch wenn die Initialisierung von einer Funktion anstelle des parameterlosen Konstruktors des lazily erstellten Typs ausgeführt wird.

Anmerkung

Ein Beispiel, das veranschaulicht, wie dieser Konstruktor in Singlethread-Szenarien (angeben LazyThreadSafetyMode.None für mode) verwendet wird, finden Sie im Lazy<T>(Boolean)-Konstruktor. Ein Beispiel, das veranschaulicht, wie Sie diesen Konstruktor verwenden können, um Sperre anstelle von Racebedingungen in Multithread-Szenarien bereitzustellen (angeben LazyThreadSafetyMode.ExecutionAndPublication für mode), finden Sie im Lazy<T>()-Konstruktor.

Im Beispiel wird eine LargeObject Klasse definiert, die von mehreren Threads lazily initialisiert wird. Die vier hauptabschnitte des Codes veranschaulichen die Erstellung des Initialisierungsprogramms, die tatsächliche Initialisierung, die Initialisierungsfunktion und den Konstruktor und den Finalizer der LargeObject-Klasse. Am Anfang der Main-Methode erstellt das Beispiel das Lazy<T>-Objekt, das eine faule Initialisierung der LargeObjectdurchführt:

lazyLargeObject = new Lazy<LargeObject>(InitLargeObject,
                             LazyThreadSafetyMode.PublicationOnly);
let lazyLargeObject = Lazy<LargeObject>(initLargeObject, LazyThreadSafetyMode.PublicationOnly)
lazyLargeObject = New Lazy(Of LargeObject)(AddressOf InitLargeObject, _
     LazyThreadSafetyMode.PublicationOnly)

Der faule Initialisierer verwendet eine Funktion, um die Initialisierung auszuführen. In diesem Fall ist eine Funktion erforderlich, da für die LargeObject-Klasse kein parameterloser Konstruktor vorhanden ist.

Das Beispiel erstellt und startet drei Threads, die für ein ManualResetEvent -Objekt blockieren, damit das Beispiel die Threads auf einmal freigeben kann. In der ThreadProc-Methode, die von allen drei Threads verwendet wird, erstellt das Aufrufen der Value-Eigenschaft die LargeObject Instanz:

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

Im dritten Schlüsselabschnitt des Codes wird die faule Initialisierungsfunktion aufgerufen, um die LargeObject Instanz zu erstellen. Die Funktion löst eine Ausnahme aus, wenn sie zum ersten Mal aufgerufen wird:

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

Bei allen anderen LazyThreadSafetyMode Einstellung wird eine unbehandelte Ausnahme in der Initialisierungsfunktion zwischengespeichert. LazyThreadSafetyMode.PublicationOnly unterdrückt jedoch das Zwischenspeichern von Ausnahmen. Die Ausgabe aus dem Beispiel zeigt, dass ein anschließender Versuch, das Objekt zu initialisieren, erfolgreich ist.

Anmerkung

Die Ausnahmemeldung wird in der Regel nach Nachrichten angezeigt, die angeben, dass andere Threads das Objekt erfolgreich initialisiert haben. Dies liegt an der Verzögerung, die durch Auslösen und Abfangen der Ausnahme eingeführt wurde.

Da der Konstruktor für die Lazy<T> Instanz LazyThreadSafetyMode.PublicationOnlyangegeben wurde, dürfen alle drei Threads LargeObject Instanzen erstellen. Im Beispiel wird dies veranschaulicht, indem Konsolenmeldungen im Konstruktor und im Finalizer der LargeObject-Klasse angezeigt werden:

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

Das Lazy<T>-Objekt stellt sicher, dass nur eine Instanz von allen Threads verwendet wird (mit Ausnahme des Threads, in dem die Initialisierungsfunktion eine Ausnahme auslöst). Die Ausgabe aus dem Beispiel zeigt dies.

Anmerkung

Aus Gründen der Einfachheit wird in diesem Beispiel eine globale Instanz von Lazy<T>verwendet, und alle Methoden sind static (Shared in Visual Basic). Dies sind keine Anforderungen für die Verwendung der faulen Initialisierung.

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
'

Hinweise

Der Threadsicherheitsmodus einer Lazy<T> Instanz beschreibt das Verhalten, wenn mehrere Threads versuchen, die Lazy<T> Instanz zu initialisieren.

Ausnahmen, die von valueFactory ausgelöst werden, werden zwischengespeichert, es sei denn, mode ist LazyThreadSafetyMode.PublicationOnly. Weitere Informationen finden Sie in der Lazy<T> Klasse oder in der System.Threading.LazyThreadSafetyMode Enumeration.

Weitere Informationen

Gilt für: