Lazy<T> Constructors
Definitie
Belangrijk
Bepaalde informatie heeft betrekking op een voorlopige productversie die aanzienlijk kan worden gewijzigd voordat deze wordt uitgebracht. Microsoft biedt geen enkele expliciete of impliciete garanties met betrekking tot de informatie die hier wordt verstrekt.
Initialiseert een nieuw exemplaar van de Lazy<T> klasse.
Overloads
| Name | Description |
|---|---|
| Lazy<T>() |
Initialiseert een nieuw exemplaar van de Lazy<T> klasse. Wanneer luie initialisatie plaatsvindt, wordt de parameterloze constructor van het doeltype gebruikt. |
| Lazy<T>(Boolean) |
Initialiseert een nieuw exemplaar van de Lazy<T> klasse. Wanneer luie initialisatie plaatsvindt, worden de parameterloze constructor van het doeltype en de opgegeven initialisatiemodus gebruikt. |
| Lazy<T>(Func<T>) |
Initialiseert een nieuw exemplaar van de Lazy<T> klasse. Wanneer luie initialisatie plaatsvindt, wordt de opgegeven initialisatiefunctie gebruikt. |
| Lazy<T>(LazyThreadSafetyMode) |
Initialiseert een nieuw exemplaar van de Lazy<T> klasse die gebruikmaakt van de parameterloze constructor van |
| Lazy<T>(T) |
Initialiseert een nieuwe instantie van de Lazy<T> klasse die gebruikmaakt van een vooraf geïnitialiseerde opgegeven waarde. |
| Lazy<T>(Func<T>, Boolean) |
Initialiseert een nieuw exemplaar van de Lazy<T> klasse. Wanneer luie initialisatie plaatsvindt, worden de opgegeven initialisatiefunctie en de initialisatiemodus gebruikt. |
| Lazy<T>(Func<T>, LazyThreadSafetyMode) |
Initialiseert een nieuw exemplaar van de Lazy<T> klasse die gebruikmaakt van de opgegeven initialisatiefunctie en de threadveiligheidsmodus. |
Lazy<T>()
- Bron:
- Lazy.cs
- Bron:
- Lazy.cs
- Bron:
- Lazy.cs
- Bron:
- Lazy.cs
- Bron:
- Lazy.cs
Initialiseert een nieuw exemplaar van de Lazy<T> klasse. Wanneer luie initialisatie plaatsvindt, wordt de parameterloze constructor van het doeltype gebruikt.
public:
Lazy();
public Lazy();
Public Sub New ()
Voorbeelden
In het volgende voorbeeld ziet u het gebruik van deze constructor. Het illustreert ook het gebruik van de Lazy<T>(Boolean) constructor (opgeven voor trueisThreadSafe) en de Lazy<T>(LazyThreadSafetyMode) constructor (opgeven voor LazyThreadSafetyMode.ExecutionAndPublicationmode). Als u wilt overschakelen naar een andere constructor, hoeft u alleen te wijzigen welke constructors als commentaar worden weergegeven.
In het voorbeeld wordt een LargeObject klasse gedefinieerd die lazily wordt geïnitialiseerd door een van de verschillende threads. De twee belangrijkste coderegels in dit voorbeeld zijn het maken van de initialisatie en de werkelijke initialisatie. Aan het begin van de Main methode maakt het voorbeeld de thread-safe lazy initializer voor 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);
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)
In het voorbeeld worden drie threads gemaakt en gestart die op een ManualResetEvent object worden geblokkeerd, zodat het voorbeeld de threads allemaal tegelijk kan vrijgeven. De ThreadProc methode die wordt gebruikt door alle drie de threads roept de Value eigenschap aan om het LargeObject exemplaar op te halen:
LargeObject large = lazyLargeObject.Value;
Dim large As LargeObject = lazyLargeObject.Value
De Lazy<T> klasse biedt vergrendeling, zodat slechts één thread het LargeObject exemplaar mag maken. In het voorbeeld ziet u dat de andere threads allemaal hetzelfde exemplaar krijgen.
Note
Ter vereenvoudiging gebruikt dit voorbeeld een globaal exemplaar van Lazy<T> en alle methoden zijn static (Shared in Visual Basic). Dit zijn geen vereisten voor het gebruik van luie initialisatie.
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
*/
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
Opmerkingen
Een exemplaar dat met deze constructor wordt gemaakt, kan gelijktijdig worden gebruikt vanuit meerdere threads.
De threadveiligheidsmodus van een Lazy<T> exemplaar dat met deze constructor wordt geïnitialiseerd, is LazyThreadSafetyMode.ExecutionAndPublication. In de veiligheidsmodus voor threads wordt het gedrag beschreven wanneer meerdere threads proberen het Lazy<T> exemplaar te initialiseren.
Een Lazy<T> exemplaar dat met deze constructor wordt gemaakt, slaat geen uitzonderingen in de cache op. Zie de Lazy<T> klasse of de System.Threading.LazyThreadSafetyMode opsomming voor meer informatie.
Zie ook
Van toepassing op
Lazy<T>(Boolean)
- Bron:
- Lazy.cs
- Bron:
- Lazy.cs
- Bron:
- Lazy.cs
- Bron:
- Lazy.cs
- Bron:
- Lazy.cs
Initialiseert een nieuw exemplaar van de Lazy<T> klasse. Wanneer luie initialisatie plaatsvindt, worden de parameterloze constructor van het doeltype en de opgegeven initialisatiemodus gebruikt.
public:
Lazy(bool isThreadSafe);
public Lazy(bool isThreadSafe);
new Lazy<'T> : bool -> Lazy<'T>
Public Sub New (isThreadSafe As Boolean)
Parameters
- isThreadSafe
- Boolean
true om dit exemplaar gelijktijdig bruikbaar te maken door meerdere threads; false om het exemplaar slechts met één thread tegelijk bruikbaar te maken.
Voorbeelden
In het volgende voorbeeld wordt het gebruik van deze constructor gedemonstreerd om een luie initialisatiefunctie te maken die niet threadveilig is, voor scenario's waarin alle toegang tot het vertraagde geïnitialiseerde object op dezelfde thread plaatsvindt. Ook wordt het gebruik van de Lazy<T>(LazyThreadSafetyMode) constructor gedemonstreerd (opgeven voor LazyThreadSafetyMode.Nonemode. Als u wilt overschakelen naar een andere constructor, wijzigt u gewoon welke constructor als commentaar wordt gemarkeerd.
Note
Zie het voorbeeld voor de true constructor voor code die laat zien hoe u deze constructor gebruikt in scenario's met meerderereads (opgeven voor).isThreadSafeLazy<T>()
In het voorbeeld wordt een LargeObject klasse gedefinieerd die lazily wordt geïnitialiseerd. In de Main methode wordt in het voorbeeld een Lazy<T> exemplaar gemaakt en vervolgens onderbroken. Wanneer u op Enter drukt, krijgt het voorbeeld toegang tot de Value eigenschap van het Lazy<T> exemplaar, waardoor initialisatie wordt veroorzaakt. De constructor van de LargeObject klasse geeft een consolebericht weer.
Note
Ter vereenvoudiging gebruikt dit voorbeeld een globaal exemplaar van Lazy<T> en alle methoden zijn static (Shared in Visual Basic). Dit zijn geen vereisten voor het gebruik van luie initialisatie.
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
Opmerkingen
De threadveiligheidsmodus van een Lazy<T> exemplaar dat met deze constructor wordt geïnitialiseerd, is als LazyThreadSafetyMode.ExecutionAndPublication dat het geval isThreadSafeistrue; anders is LazyThreadSafetyMode.Nonede modus. In de veiligheidsmodus voor threads wordt het gedrag beschreven wanneer meerdere threads proberen het Lazy<T> exemplaar te initialiseren. Als u de LazyThreadSafetyMode.PublicationOnly modus wilt opgeven, gebruikt u de Lazy<T>(Func<T>, LazyThreadSafetyMode) of Lazy<T>(LazyThreadSafetyMode) constructor.
Een Lazy<T> exemplaar dat met deze constructor wordt gemaakt, slaat geen uitzonderingen in de cache op. Zie de Lazy<T> klasse of de System.Threading.LazyThreadSafetyMode opsomming voor meer informatie.
Zie ook
Van toepassing op
Lazy<T>(Func<T>)
- Bron:
- Lazy.cs
- Bron:
- Lazy.cs
- Bron:
- Lazy.cs
- Bron:
- Lazy.cs
- Bron:
- Lazy.cs
Initialiseert een nieuw exemplaar van de Lazy<T> klasse. Wanneer luie initialisatie plaatsvindt, wordt de opgegeven initialisatiefunctie gebruikt.
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))
Parameters
- valueFactory
- Func<T>
De gemachtigde die wordt aangeroepen om de vertraagde geïnitialiseerde waarde te produceren wanneer deze nodig is.
Uitzonderingen
valueFactory is null.
Voorbeelden
In het volgende voorbeeld ziet u hoe deze constructor wordt gebruikt om luie initialisatie te bieden met uitzondering van caching. Het toont ook het gebruik van de Lazy<T>(Func<T>, Boolean) constructor (opgeven voor trueisThreadSafe) en de Lazy<T>(Func<T>, LazyThreadSafetyMode) constructor (opgeven voor LazyThreadSafetyMode.ExecutionAndPublicationmode). Als u wilt overschakelen naar een andere constructor, hoeft u alleen te wijzigen welke constructors als commentaar worden weergegeven.
In het voorbeeld wordt een LargeObject klasse gedefinieerd die lazily wordt geïnitialiseerd door een van de verschillende threads. De drie belangrijkste secties met code illustreren het maken van de initialisatie, de werkelijke initialisatie en de constructor van de LargeObject klasse, die uitzonderingscaching laat zien. Aan het begin van de Main methode maakt het voorbeeld de thread-safe lazy initializer voor 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)
In het voorbeeld worden drie threads gemaakt en gestart. De ThreadProc methode die wordt gebruikt door alle drie de threads roept de Value eigenschap aan om het LargeObject exemplaar op te halen:
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
In de constructor van de LargeObject klasse genereert de derde sleutelsectie van code een uitzondering wanneer een LargeObject instantie voor het eerst wordt gemaakt, maar daarna kan het maken van exemplaren plaatsvinden:
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
Wanneer het voorbeeld wordt uitgevoerd, wordt de eerste thread die probeert een exemplaar van LargeObject een storing te maken en wordt de uitzondering onderschept. U kunt verwachten dat de volgende thread een exemplaar zou maken, maar dat het Lazy<T> object de uitzondering in de cache heeft opgeslagen. Daarom gooien alle drie de threads de uitzondering.
Note
Ter vereenvoudiging gebruikt dit voorbeeld een globaal exemplaar van Lazy<T> en alle methoden zijn static (Shared in Visual Basic). Dit zijn geen vereisten voor het gebruik van luie initialisatie.
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
'
Opmerkingen
Een exemplaar dat met deze constructor wordt gemaakt, kan gelijktijdig worden gebruikt vanuit meerdere threads.
De threadveiligheidsmodus van een Lazy<T> exemplaar dat met deze constructor wordt geïnitialiseerd, is LazyThreadSafetyMode.ExecutionAndPublication. In de veiligheidsmodus voor threads wordt het gedrag beschreven wanneer meerdere threads proberen het Lazy<T> exemplaar te initialiseren.
Uitzonderingen die worden gegenereerd door valueFactory , worden in de cache opgeslagen. Zie de Lazy<T> klasse of de System.Threading.LazyThreadSafetyMode opsomming voor meer informatie.
Zie ook
Van toepassing op
Lazy<T>(LazyThreadSafetyMode)
- Bron:
- Lazy.cs
- Bron:
- Lazy.cs
- Bron:
- Lazy.cs
- Bron:
- Lazy.cs
- Bron:
- Lazy.cs
Initialiseert een nieuw exemplaar van de Lazy<T> klasse die gebruikmaakt van de parameterloze constructor van T en de opgegeven thread-safety-modus.
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)
Parameters
- mode
- LazyThreadSafetyMode
Een van de opsommingswaarden waarmee de veiligheidsmodus voor threads wordt opgegeven.
Uitzonderingen
mode bevat een ongeldige waarde.
Voorbeelden
In het volgende voorbeeld wordt het gebruik van deze constructor gedemonstreerd om een luie initialisatiefunctie te maken waarmee meerdere threads kunnen racen om een object lui te maken. Meerdere threads kunnen slagen in het maken van exemplaren, maar alle threads gebruiken het exemplaar dat eerst is gemaakt.
Note
Zie de LazyThreadSafetyMode.None constructor voor een voorbeeld dat laat zien hoe u deze constructor gebruikt in scenario's met één thread (opgeven voor).modeLazy<T>(Boolean) Zie de constructor voor een voorbeeld waarin wordt gedemonstreerd hoe u deze constructor kunt gebruiken om vergrendeling te bieden in plaats van racevoorwaarden in scenario's met meerderereads (opgeven LazyThreadSafetyMode.ExecutionAndPublication voor mode), raadpleegt u de Lazy<T>() constructor.
In het voorbeeld wordt een LargeObject klasse gedefinieerd die lazily wordt geïnitialiseerd door een van de verschillende threads. De drie belangrijkste secties van code illustreren het maken van de initialisatie, de werkelijke initialisatie en de constructor en finalizer van de LargeObject klasse. Aan het begin van de Main methode maakt het voorbeeld het Lazy<T> object dat luie initialisatie van het LargeObjectvolgende uitvoert:
lazyLargeObject = new Lazy<LargeObject>(LazyThreadSafetyMode.PublicationOnly);
let lazyLargeObject = Lazy<LargeObject> LazyThreadSafetyMode.PublicationOnly
lazyLargeObject = New Lazy(Of LargeObject)(LazyThreadSafetyMode.PublicationOnly)
In het voorbeeld worden drie threads gemaakt en gestart die op een ManualResetEvent object worden geblokkeerd, zodat het voorbeeld de threads allemaal tegelijk kan vrijgeven. In de ThreadProc methode die wordt gebruikt door alle drie de threads, maakt het aanroepen van de Value eigenschap het LargeObject exemplaar:
LargeObject large = lazyLargeObject.Value;
let large = lazyLargeObject.Value
Dim large As LargeObject = lazyLargeObject.Value
Omdat de constructor voor het Lazy<T> opgegeven LazyThreadSafetyMode.PublicationOnlyexemplaar alle drie threads mag maken LargeObject . In het voorbeeld ziet u dit door consoleberichten weer te geven in de constructor en in de finalizer van de LargeObject klasse:
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
Het Lazy<T> object zorgt er echter voor dat slechts één exemplaar wordt gebruikt door alle threads. In de uitvoer van het voorbeeld ziet u dat alle drie de threads gebruikmaken van hetzelfde exemplaar en ook dat de andere twee exemplaren kunnen worden vrijgemaakt door garbagecollection.
Note
Ter vereenvoudiging gebruikt dit voorbeeld een globaal exemplaar van Lazy<T> en alle methoden zijn static (Shared in Visual Basic). Dit zijn geen vereisten voor het gebruik van luie initialisatie.
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
'
Opmerkingen
In de veiligheidsmodus voor threads van een Lazy<T> exemplaar wordt het gedrag beschreven wanneer meerdere threads proberen het Lazy<T> exemplaar te initialiseren.
Een Lazy<T> exemplaar dat met deze constructor wordt gemaakt, slaat geen uitzonderingen in de cache op. Zie de Lazy<T> klasse of de System.Threading.LazyThreadSafetyMode opsomming voor meer informatie.
Zie ook
Van toepassing op
Lazy<T>(T)
- Bron:
- Lazy.cs
- Bron:
- Lazy.cs
- Bron:
- Lazy.cs
- Bron:
- Lazy.cs
- Bron:
- Lazy.cs
Initialiseert een nieuwe instantie van de Lazy<T> klasse die gebruikmaakt van een vooraf geïnitialiseerde opgegeven waarde.
public:
Lazy(T value);
public Lazy(T value);
new Lazy<'T> : 'T -> Lazy<'T>
Public Sub New (value As T)
Parameters
- value
- T
De vooraf gedefinieerde waarde die moet worden gebruikt.
Opmerkingen
Een exemplaar dat met deze constructor is gemaakt, kan gelijktijdig door meerdere threads worden gebruikt.
Van toepassing op
Lazy<T>(Func<T>, Boolean)
- Bron:
- Lazy.cs
- Bron:
- Lazy.cs
- Bron:
- Lazy.cs
- Bron:
- Lazy.cs
- Bron:
- Lazy.cs
Initialiseert een nieuw exemplaar van de Lazy<T> klasse. Wanneer luie initialisatie plaatsvindt, worden de opgegeven initialisatiefunctie en de initialisatiemodus gebruikt.
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)
Parameters
- valueFactory
- Func<T>
De gemachtigde die wordt aangeroepen om de vertraagde geïnitialiseerde waarde te produceren wanneer deze nodig is.
- isThreadSafe
- Boolean
true om dit exemplaar gelijktijdig bruikbaar te maken door meerdere threads; false om dit exemplaar bruikbaar te maken voor slechts één thread tegelijk.
Uitzonderingen
valueFactory is null.
Voorbeelden
In het volgende voorbeeld wordt het gebruik van deze constructor gedemonstreerd om luie initialisatie te bieden met uitzonderingscaching, in een scenario met één thread. Ook wordt het gebruik van de Lazy<T> constructor gedemonstreerd (opgeven voor LazyThreadSafetyMode.Nonemode). Als u wilt overschakelen naar die constructor, wijzigt u gewoon welke constructor als commentaar wordt weergegeven.
Note
Zie het voorbeeld voor de true constructor voor code die laat zien hoe u deze constructor gebruikt in scenario's met meerderereads (opgeven voor).isThreadSafeLazy<T>(Func<T>)
In het voorbeeld wordt een LargeObject klasse gedefinieerd die lazily wordt geïnitialiseerd door een van de verschillende threads. De drie belangrijkste secties met code illustreren het maken van de initialisatie, de werkelijke initialisatie en de constructor van de LargeObject klasse, die uitzonderingscaching laat zien. Aan het begin van de Main methode maakt het voorbeeld de thread-safe lazy initializer voor 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)
In de aanroep van de constructor is isThreadSafede false parameter , dus de Lazy<T> is niet thread veilig. Omdat het niet thread veilig is, roept het voorbeeld de Value eigenschap drie keer aan op dezelfde thread:
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
In de constructor van de LargeObject klasse genereert de derde sleutelsectie van code een uitzondering wanneer een LargeObject instantie voor het eerst wordt gemaakt, maar daarna kan het maken van exemplaren plaatsvinden:
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
Wanneer het voorbeeld wordt uitgevoerd, wordt de eerste poging om een exemplaar van LargeObject een storing te maken en wordt de uitzondering onderschept. U kunt verwachten dat de volgende poging zou slagen, maar het Lazy<T> object heeft de uitzondering in de cache opgeslagen. Daarom werpen alle drie de pogingen de uitzondering op.
Note
Ter vereenvoudiging gebruikt dit voorbeeld een globaal exemplaar van Lazy<T> en alle methoden zijn static (Shared in Visual Basic). Dit zijn geen vereisten voor het gebruik van luie initialisatie.
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
'
Opmerkingen
De threadveiligheidsmodus van een Lazy<T> exemplaar dat met deze constructor wordt geïnitialiseerd, is als LazyThreadSafetyMode.ExecutionAndPublication dat het geval isThreadSafeistrue; anders is LazyThreadSafetyMode.Nonede modus. In de veiligheidsmodus voor threads wordt het gedrag beschreven wanneer meerdere threads proberen het Lazy<T> exemplaar te initialiseren.
Als u de LazyThreadSafetyMode.PublicationOnly modus wilt opgeven, gebruikt u de Lazy<T>(Func<T>, LazyThreadSafetyMode) of Lazy<T>(LazyThreadSafetyMode) constructor.
Uitzonderingen die worden gegenereerd door valueFactory , worden in de cache opgeslagen. Zie de Lazy<T> klasse of de System.Threading.LazyThreadSafetyMode opsomming voor meer informatie.
Zie ook
Van toepassing op
Lazy<T>(Func<T>, LazyThreadSafetyMode)
- Bron:
- Lazy.cs
- Bron:
- Lazy.cs
- Bron:
- Lazy.cs
- Bron:
- Lazy.cs
- Bron:
- Lazy.cs
Initialiseert een nieuw exemplaar van de Lazy<T> klasse die gebruikmaakt van de opgegeven initialisatiefunctie en de threadveiligheidsmodus.
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)
Parameters
- valueFactory
- Func<T>
De gemachtigde die wordt aangeroepen om de vertraagde geïnitialiseerde waarde te produceren wanneer deze nodig is.
- mode
- LazyThreadSafetyMode
Een van de opsommingswaarden waarmee de veiligheidsmodus voor threads wordt opgegeven.
Uitzonderingen
mode bevat een ongeldige waarde.
valueFactory is null.
Voorbeelden
In het volgende voorbeeld wordt het gebruik van deze constructor gedemonstreerd om een luie initialisatiefunctie te maken waarmee meerdere threads kunnen racen om een object lui te maken. Meerdere threads kunnen slagen in het maken van exemplaren, maar alle threads gebruiken het exemplaar dat eerst is gemaakt. Bovendien laat het voorbeeld zien dat uitzonderingen nooit in de cache worden opgeslagen wanneer u opgeeft LazyThreadSafetyMode.PublicationOnly, zelfs als initialisatie wordt uitgevoerd door een functie in plaats van door de parameterloze constructor van het lui gemaakte type.
Note
Zie de LazyThreadSafetyMode.None constructor voor een voorbeeld dat laat zien hoe u deze constructor gebruikt in scenario's met één thread (opgeven voor).modeLazy<T>(Boolean) Zie de constructor voor een voorbeeld waarin wordt gedemonstreerd hoe u deze constructor kunt gebruiken om vergrendeling te bieden in plaats van racevoorwaarden in scenario's met meerderereads (opgeven LazyThreadSafetyMode.ExecutionAndPublication voor mode), raadpleegt u de Lazy<T>() constructor.
In het voorbeeld wordt een LargeObject klasse gedefinieerd die lazily wordt geïnitialiseerd door een van de verschillende threads. De vier belangrijke secties van code illustreren het maken van de initialisatie, de werkelijke initialisatie, de initialisatiefunctie en de constructor en finalizer van de LargeObject klasse. Aan het begin van de Main methode maakt het voorbeeld het Lazy<T> object dat luie initialisatie van het LargeObjectvolgende uitvoert:
lazyLargeObject = new Lazy<LargeObject>(InitLargeObject,
LazyThreadSafetyMode.PublicationOnly);
let lazyLargeObject = Lazy<LargeObject>(initLargeObject, LazyThreadSafetyMode.PublicationOnly)
lazyLargeObject = New Lazy(Of LargeObject)(AddressOf InitLargeObject, _
LazyThreadSafetyMode.PublicationOnly)
De luie initialisatiefunctie gebruikt een functie om de initialisatie uit te voeren. In dit geval is een functie vereist omdat er geen parameterloze constructor voor de LargeObject klasse is.
In het voorbeeld worden drie threads gemaakt en gestart die op een ManualResetEvent object worden geblokkeerd, zodat het voorbeeld de threads allemaal tegelijk kan vrijgeven. In de ThreadProc methode die wordt gebruikt door alle drie de threads, maakt het aanroepen van de Value eigenschap het LargeObject exemplaar:
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
In de derde sleutelsectie van de code wordt de luie initialisatiefunctie aangeroepen om het LargeObject exemplaar te maken. De functie genereert een uitzondering de eerste keer dat deze wordt aangeroepen:
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
Met een andere LazyThreadSafetyMode instelling wordt een niet-verwerkte uitzondering in de initialisatiefunctie in de cache opgeslagen. LazyThreadSafetyMode.PublicationOnly Onderdrukt echter uitzonderingscaching. De uitvoer van het voorbeeld laat zien dat een volgende poging om het object te initialiseren slaagt.
Note
Het uitzonderingsbericht wordt meestal weergegeven nadat berichten die aangeven dat andere threads het object hebben geïnitialiseerd. Dit komt door de vertraging die is geïntroduceerd door het gooien en vangen van de uitzondering.
Omdat de constructor voor het Lazy<T> opgegeven LazyThreadSafetyMode.PublicationOnlyexemplaar alle drie threads mag maken LargeObject . In het voorbeeld ziet u dit door consoleberichten weer te geven in de constructor en in de finalizer van de LargeObject klasse:
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
Het Lazy<T> object zorgt ervoor dat slechts één exemplaar wordt gebruikt door alle threads (behalve de thread waarbij de initialisatiefunctie een uitzondering genereert). In de uitvoer uit het voorbeeld ziet u dit.
Note
Ter vereenvoudiging gebruikt dit voorbeeld een globaal exemplaar van Lazy<T> en alle methoden zijn static (Shared in Visual Basic). Dit zijn geen vereisten voor het gebruik van luie initialisatie.
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
'
Opmerkingen
In de veiligheidsmodus voor threads van een Lazy<T> exemplaar wordt het gedrag beschreven wanneer meerdere threads proberen het Lazy<T> exemplaar te initialiseren.
Uitzonderingen die worden gegenereerd door valueFactory , worden in de cache opgeslagen, tenzij modeLazyThreadSafetyMode.PublicationOnly. Zie de Lazy<T> klasse of de System.Threading.LazyThreadSafetyMode opsomming voor meer informatie.