Lazy<T> Constructeurs
Définition
Important
Certaines informations portent sur la préversion du produit qui est susceptible d’être en grande partie modifiée avant sa publication. Microsoft exclut toute garantie, expresse ou implicite, concernant les informations fournies ici.
Initialise une nouvelle instance de la classe Lazy<T>.
Surcharges
Lazy<T>() |
Initialise une nouvelle instance de la classe Lazy<T>. Lorsque l’initialisation différée se produit, le constructeur sans paramètre du type cible est utilisé. |
Lazy<T>(Boolean) |
Initialise une nouvelle instance de la classe Lazy<T>. Lorsque l’initialisation différée se produit, le constructeur sans paramètre du type cible et le mode d’initialisation spécifié sont utilisés. |
Lazy<T>(Func<T>) |
Initialise une nouvelle instance de la classe Lazy<T>. Lorsque l’initialisation différée se produit, la fonction d’initialisation spécifiée est utilisée. |
Lazy<T>(LazyThreadSafetyMode) |
Initialise une nouvelle instance de la classe Lazy<T> qui utilise le constructeur sans paramètre de |
Lazy<T>(T) |
Initialise une nouvelle instance de la classe Lazy<T> qui utilise une valeur spécifiée préinitialisée. |
Lazy<T>(Func<T>, Boolean) |
Initialise une nouvelle instance de la classe Lazy<T>. Lorsque l’initialisation différée se produit, la fonction d’initialisation et le mode d’initialisation spécifiés sont utilisés. |
Lazy<T>(Func<T>, LazyThreadSafetyMode) |
Initialise une nouvelle instance de la classe Lazy<T> qui utilise la fonction d’initialisation et le mode de sécurité des threads spécifiés. |
Lazy<T>()
- Source:
- Lazy.cs
- Source:
- Lazy.cs
- Source:
- Lazy.cs
Initialise une nouvelle instance de la classe Lazy<T>. Lorsque l’initialisation différée se produit, le constructeur sans paramètre du type cible est utilisé.
public:
Lazy();
public Lazy ();
Public Sub New ()
Exemples
L’exemple suivant illustre l’utilisation de ce constructeur. Il illustre également l’utilisation du constructeur Lazy<T>(Boolean) (spécification de true
pour isThreadSafe
) et du constructeur Lazy<T>(LazyThreadSafetyMode) (spécification de LazyThreadSafetyMode.ExecutionAndPublication pour mode
). Pour basculer vers un autre constructeur, modifiez simplement les constructeurs qui sont commentés.
L’exemple définit une classe LargeObject
qui sera initialisée de manière différée par l’un de plusieurs threads. Les deux lignes de code clés de cet exemple sont la création de l’initialiseur et l’initialisation réelle. Au début de la méthode Main
, l’exemple crée l’initialiseur différé thread-safe pour 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)
L’exemple crée et démarre trois threads qui bloquent sur un objet ManualResetEvent, afin que l’exemple puisse libérer tous les threads en même temps. La méthode ThreadProc
utilisée par les trois threads appelle la propriété Value pour obtenir l’instance LargeObject
:
LargeObject large = lazyLargeObject.Value;
let large = lazyLargeObject.Value
Dim large As LargeObject = lazyLargeObject.Value
La classe Lazy<T> fournit un verrouillage, afin qu’un seul thread soit autorisé à créer l’instance LargeObject
. L’exemple montre que les autres threads obtiennent toutes la même instance.
Note
Par souci de simplicité, cet exemple utilise une instance globale de Lazy<T>, et toutes les méthodes sont static
(Shared
en Visual Basic). Ces conditions ne sont pas requises pour l’utilisation de l’initialisation différée.
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
Remarques
Une instance créée avec ce constructeur peut être utilisée simultanément à partir de plusieurs threads.
Le mode de sécurité de thread d’une instance de Lazy<T> initialisée avec ce constructeur est LazyThreadSafetyMode.ExecutionAndPublication. Le mode de sécurité des threads décrit le comportement lorsque plusieurs threads essaient d’initialiser l’instance Lazy<T>.
Une instance Lazy<T> créée avec ce constructeur ne met pas en cache les exceptions. Pour plus d’informations, consultez la classe Lazy<T> ou l’énumération System.Threading.LazyThreadSafetyMode.
Voir aussi
S’applique à
Lazy<T>(Boolean)
- Source:
- Lazy.cs
- Source:
- Lazy.cs
- Source:
- Lazy.cs
Initialise une nouvelle instance de la classe Lazy<T>. Lorsque l’initialisation différée se produit, le constructeur sans paramètre du type cible et le mode d’initialisation spécifié sont utilisés.
public:
Lazy(bool isThreadSafe);
public Lazy (bool isThreadSafe);
new Lazy<'T> : bool -> Lazy<'T>
Public Sub New (isThreadSafe As Boolean)
Paramètres
- isThreadSafe
- Boolean
true
pour rendre cette instance utilisable simultanément par plusieurs threads ; false
pour rendre l’instance utilisable par un seul thread à la fois.
Exemples
L’exemple suivant illustre l’utilisation de ce constructeur pour créer un initialiseur différé qui n’est pas thread-safe, pour les scénarios où tous les accès à l’objet initialisé différé se produisent sur le même thread. Il illustre également l’utilisation du constructeur Lazy<T>(LazyThreadSafetyMode) (en spécifiant LazyThreadSafetyMode.None pour mode
. Pour basculer vers un autre constructeur, modifiez simplement le constructeur qui est commenté.
Note
Pour le code qui montre comment utiliser ce constructeur dans des scénarios multithreads (en spécifiant true
pour isThreadSafe
), consultez l’exemple du constructeur Lazy<T>().
L’exemple définit une classe LargeObject
qui sera initialisée de manière différée. Dans la méthode Main
, l’exemple crée une instance de Lazy<T>, puis s’interrompt. Lorsque vous appuyez sur la touche Entrée LargeObject
affiche un message console.
Note
Par souci de simplicité, cet exemple utilise une instance globale de Lazy<T>, et toutes les méthodes sont static
(Shared
en Visual Basic). Ces conditions ne sont pas requises pour l’utilisation de l’initialisation différée.
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
Remarques
Le mode de sécurité de thread d’une instance de Lazy<T> initialisée avec ce constructeur est LazyThreadSafetyMode.ExecutionAndPublication si isThreadSafe
est true
; sinon, le mode est LazyThreadSafetyMode.None. Le mode de sécurité des threads décrit le comportement lorsque plusieurs threads essaient d’initialiser l’instance Lazy<T>. Pour spécifier le mode LazyThreadSafetyMode.PublicationOnly, utilisez le constructeur Lazy<T>(Func<T>, LazyThreadSafetyMode) ou Lazy<T>(LazyThreadSafetyMode).
Une instance Lazy<T> créée avec ce constructeur ne met pas en cache les exceptions. Pour plus d’informations, consultez la classe Lazy<T> ou l’énumération System.Threading.LazyThreadSafetyMode.
Voir aussi
S’applique à
Lazy<T>(Func<T>)
- Source:
- Lazy.cs
- Source:
- Lazy.cs
- Source:
- Lazy.cs
Initialise une nouvelle instance de la classe Lazy<T>. Lorsque l’initialisation différée se produit, la fonction d’initialisation spécifiée est utilisée.
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))
Paramètres
- valueFactory
- Func<T>
Délégué appelé pour produire la valeur initialisée de manière différée lorsqu’il est nécessaire.
Exceptions
valueFactory
est null
.
Exemples
L’exemple suivant illustre l’utilisation de ce constructeur pour fournir une initialisation différée avec mise en cache d’exception. Il illustre également l’utilisation du constructeur Lazy<T>(Func<T>, Boolean) (spécification de true
pour isThreadSafe
) et du constructeur Lazy<T>(Func<T>, LazyThreadSafetyMode) (spécification de LazyThreadSafetyMode.ExecutionAndPublication pour mode
). Pour basculer vers un autre constructeur, modifiez simplement les constructeurs qui sont commentés.
L’exemple définit une classe LargeObject
qui sera initialisée de manière différée par l’un de plusieurs threads. Les trois sections clés du code illustrent la création de l’initialiseur, l’initialisation réelle et le constructeur de la classe LargeObject
, qui illustre la mise en cache des exceptions. Au début de la méthode Main
, l’exemple crée l’initialiseur différé thread-safe pour 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)
L’exemple crée et démarre trois threads. La méthode ThreadProc
utilisée par les trois threads appelle la propriété Value pour obtenir l’instance LargeObject
:
try
{
LargeObject large = lazyLargeObject.Value;
// IMPORTANT: Lazy initialization is thread-safe, but it doesn't protect the
// object after creation. You must lock the object before accessing it,
// unless the type is thread safe. (LargeObject is not thread safe.)
lock(large)
{
large.Data[0] = Thread.CurrentThread.ManagedThreadId;
Console.WriteLine("Initialized by thread {0}; last used by thread {1}.",
large.InitializedBy, large.Data[0]);
}
}
catch (ApplicationException aex)
{
Console.WriteLine("Exception: {0}", aex.Message);
}
try
let large = lazyLargeObject.Value
// IMPORTANT: Lazy initialization is thread-safe, but it doesn't protect the
// object after creation. You must lock the object before accessing it,
// unless the type is thread safe. (LargeObject is not thread safe.)
lock large (fun () ->
large.Data[0] <- Thread.CurrentThread.ManagedThreadId
printfn $"Initialized by thread {large.InitializedBy} last used by thread {large.Data[0]}.")
with :? ApplicationException as aex ->
printfn $"Exception: {aex.Message}"
Try
Dim large As LargeObject = lazyLargeObject.Value
' IMPORTANT: Lazy initialization is thread-safe, but it doesn't protect the
' object after creation. You must lock the object before accessing it,
' unless the type is thread safe. (LargeObject is not thread safe.)
SyncLock large
large.Data(0) = Thread.CurrentThread.ManagedThreadId
Console.WriteLine("Initialized by thread {0}; last used by thread {1}.", _
large.InitializedBy, large.Data(0))
End SyncLock
Catch aex As ApplicationException
Console.WriteLine("Exception: {0}", aex.Message)
End Try
Dans le constructeur de la classe LargeObject
, la troisième section clé du code lève une exception la première fois qu’une instance de LargeObject
est créée, mais permet ensuite la création d’une instance :
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
Lorsque l’exemple est exécuté, le premier thread qui tente de créer une instance de LargeObject
échoue et l’exception est interceptée. Vous pouvez vous attendre à ce que le thread suivant crée une instance, mais que l’objet Lazy<T> a mis en cache l’exception. En raison de cela, les trois threads lèvent l’exception.
Note
Par souci de simplicité, cet exemple utilise une instance globale de Lazy<T>, et toutes les méthodes sont static
(Shared
en Visual Basic). Ces conditions ne sont pas requises pour l’utilisation de l’initialisation différée.
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
'
Remarques
Une instance créée avec ce constructeur peut être utilisée simultanément à partir de plusieurs threads.
Le mode de sécurité de thread d’une instance de Lazy<T> initialisée avec ce constructeur est LazyThreadSafetyMode.ExecutionAndPublication. Le mode de sécurité des threads décrit le comportement lorsque plusieurs threads essaient d’initialiser l’instance Lazy<T>.
Les exceptions levées par valueFactory
sont mises en cache. Pour plus d’informations, consultez la classe Lazy<T> ou l’énumération System.Threading.LazyThreadSafetyMode.
Voir aussi
S’applique à
Lazy<T>(LazyThreadSafetyMode)
- Source:
- Lazy.cs
- Source:
- Lazy.cs
- Source:
- Lazy.cs
Initialise une nouvelle instance de la classe Lazy<T> qui utilise le constructeur sans paramètre de T
et le mode de sécurité de thread spécifié.
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)
Paramètres
- mode
- LazyThreadSafetyMode
Une des valeurs d’énumération qui spécifie le mode de sécurité du thread.
Exceptions
mode
contient une valeur non valide.
Exemples
L’exemple suivant illustre l’utilisation de ce constructeur pour créer un initialiseur différé qui permet à plusieurs threads de se courser pour créer un objet de manière différée. Plusieurs threads peuvent réussir à créer des instances, mais tous les threads utilisent l’instance créée en premier.
Note
Pour obtenir un exemple qui montre comment utiliser ce constructeur dans des scénarios à thread unique (en spécifiant LazyThreadSafetyMode.None pour mode
), consultez le constructeur Lazy<T>(Boolean). Pour obtenir un exemple qui montre comment utiliser ce constructeur pour fournir un verrouillage au lieu de conditions de concurrence dans des scénarios multithreads (en spécifiant LazyThreadSafetyMode.ExecutionAndPublication pour mode
), consultez le constructeur Lazy<T>().
L’exemple définit une classe LargeObject
qui sera initialisée de manière différée par l’un des plusieurs threads. Les trois sections clés du code illustrent la création de l’initialiseur, l’initialisation réelle et le constructeur et le finaliseur de la classe LargeObject
. Au début de la méthode Main
, l’exemple crée l’objet Lazy<T> qui effectue une initialisation différée du LargeObject
:
lazyLargeObject = new Lazy<LargeObject>(LazyThreadSafetyMode.PublicationOnly);
let lazyLargeObject = Lazy<LargeObject> LazyThreadSafetyMode.PublicationOnly
lazyLargeObject = New Lazy(Of LargeObject)(LazyThreadSafetyMode.PublicationOnly)
L’exemple crée et démarre trois threads qui bloquent sur un objet ManualResetEvent, afin que l’exemple puisse libérer tous les threads en même temps. Dans la méthode ThreadProc
utilisée par les trois threads, l’appel de la propriété Value crée l’instance LargeObject
:
LargeObject large = lazyLargeObject.Value;
let large = lazyLargeObject.Value
Dim large As LargeObject = lazyLargeObject.Value
Étant donné que le constructeur de l’instance Lazy<T> spécifiée LazyThreadSafetyMode.PublicationOnly, les trois threads sont autorisés à créer des instances LargeObject
. L’exemple illustre cela en affichant les messages de console dans le constructeur et dans le finaliseur de la classe LargeObject
:
public LargeObject()
{
initBy = Thread.CurrentThread.ManagedThreadId;
Console.WriteLine("Constructor: Instance initializing on thread {0}", initBy);
}
~LargeObject()
{
Console.WriteLine("Finalizer: Instance was initialized on {0}", initBy);
}
type LargeObject() =
let initBy = Thread.CurrentThread.ManagedThreadId
do
printfn $"Constructor: Instance initializing on thread {initBy}"
override _.Finalize() =
printfn $"Finalizer: Instance was initialized on {initBy}"
Public Sub New()
initBy = Thread.CurrentThread.ManagedThreadId
Console.WriteLine("Constructor: Instance initializing on thread {0}", initBy)
End Sub
Protected Overrides Sub Finalize()
Console.WriteLine("Finalizer: Instance was initialized on {0}", initBy)
End Sub
Toutefois, l’objet Lazy<T> garantit qu’une seule instance est utilisée par tous les threads. La sortie de l’exemple montre que les trois threads utilisent la même instance et montrent également que les deux autres instances peuvent être récupérées par garbage collection.
Note
Par souci de simplicité, cet exemple utilise une instance globale de Lazy<T>, et toutes les méthodes sont static
(Shared
en Visual Basic). Ces conditions ne sont pas requises pour l’utilisation de l’initialisation différée.
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
'
Remarques
Le mode de sécurité de thread d’une instance de Lazy<T> décrit le comportement lorsque plusieurs threads essaient d’initialiser l’instance Lazy<T>.
Une instance Lazy<T> créée avec ce constructeur ne met pas en cache les exceptions. Pour plus d’informations, consultez la classe Lazy<T> ou l’énumération System.Threading.LazyThreadSafetyMode.
Voir aussi
S’applique à
Lazy<T>(T)
- Source:
- Lazy.cs
- Source:
- Lazy.cs
- Source:
- Lazy.cs
Initialise une nouvelle instance de la classe Lazy<T> qui utilise une valeur spécifiée préinitialisée.
public:
Lazy(T value);
public Lazy (T value);
new Lazy<'T> : 'T -> Lazy<'T>
Public Sub New (value As T)
Paramètres
- value
- T
Valeur préinitialisée à utiliser.
Remarques
Une instance créée avec ce constructeur est utilisable simultanément par plusieurs threads.
S’applique à
Lazy<T>(Func<T>, Boolean)
- Source:
- Lazy.cs
- Source:
- Lazy.cs
- Source:
- Lazy.cs
Initialise une nouvelle instance de la classe Lazy<T>. Lorsque l’initialisation différée se produit, la fonction d’initialisation et le mode d’initialisation spécifiés sont utilisés.
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)
Paramètres
- valueFactory
- Func<T>
Délégué appelé pour produire la valeur initialisée de manière différée lorsqu’il est nécessaire.
- isThreadSafe
- Boolean
true
pour rendre cette instance utilisable simultanément par plusieurs threads ; false
pour rendre cette instance utilisable par un seul thread à la fois.
Exceptions
valueFactory
est null
.
Exemples
L’exemple suivant illustre l’utilisation de ce constructeur pour fournir une initialisation différée avec mise en cache d’exceptions, dans un scénario avec un thread unique. Il illustre également l’utilisation du constructeur Lazy<T> (en spécifiant LazyThreadSafetyMode.None pour mode
). Pour basculer vers ce constructeur, modifiez simplement le constructeur qui est commenté.
Note
Pour le code qui montre comment utiliser ce constructeur dans des scénarios multithreads (en spécifiant true
pour isThreadSafe
), consultez l’exemple du constructeur Lazy<T>(Func<T>).
L’exemple définit une classe LargeObject
qui sera initialisée de manière différée par l’un de plusieurs threads. Les trois sections clés du code illustrent la création de l’initialiseur, l’initialisation réelle et le constructeur de la classe LargeObject
, qui illustre la mise en cache des exceptions. Au début de la méthode Main
, l’exemple crée l’initialiseur différé thread-safe pour 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)
Dans l’appel au constructeur, le paramètre isThreadSafe
est false
, de sorte que le Lazy<T> n’est pas thread-safe. Étant donné qu’il n’est pas thread sécurisé, l’exemple appelle la propriété Value trois fois sur le même 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
Dans le constructeur de la classe LargeObject
, la troisième section clé du code lève une exception la première fois qu’une instance de LargeObject
est créée, mais permet ensuite la création d’une instance :
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
Lorsque l’exemple est exécuté, la première tentative de création d’une instance de LargeObject
échoue et l’exception est interceptée. Vous pouvez vous attendre à ce que la prochaine tentative réussisse, mais que l’objet Lazy<T> a mis en cache l’exception. En raison de cela, les trois tentatives lèvent l’exception.
Note
Par souci de simplicité, cet exemple utilise une instance globale de Lazy<T>, et toutes les méthodes sont static
(Shared
en Visual Basic). Ces conditions ne sont pas requises pour l’utilisation de l’initialisation différée.
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
'
Remarques
Le mode de sécurité de thread d’une instance de Lazy<T> initialisée avec ce constructeur est LazyThreadSafetyMode.ExecutionAndPublication si isThreadSafe
est true
; sinon, le mode est LazyThreadSafetyMode.None. Le mode de sécurité des threads décrit le comportement lorsque plusieurs threads essaient d’initialiser l’instance Lazy<T>.
Pour spécifier le mode LazyThreadSafetyMode.PublicationOnly, utilisez le constructeur Lazy<T>(Func<T>, LazyThreadSafetyMode) ou Lazy<T>(LazyThreadSafetyMode).
Les exceptions levées par valueFactory
sont mises en cache. Pour plus d’informations, consultez la classe Lazy<T> ou l’énumération System.Threading.LazyThreadSafetyMode.
Voir aussi
S’applique à
Lazy<T>(Func<T>, LazyThreadSafetyMode)
- Source:
- Lazy.cs
- Source:
- Lazy.cs
- Source:
- Lazy.cs
Initialise une nouvelle instance de la classe Lazy<T> qui utilise la fonction d’initialisation et le mode de sécurité des threads spécifiés.
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)
Paramètres
- valueFactory
- Func<T>
Délégué appelé pour produire la valeur initialisée de manière différée lorsqu’il est nécessaire.
- mode
- LazyThreadSafetyMode
Une des valeurs d’énumération qui spécifie le mode de sécurité du thread.
Exceptions
mode
contient une valeur non valide.
valueFactory
est null
.
Exemples
L’exemple suivant illustre l’utilisation de ce constructeur pour créer un initialiseur différé qui permet à plusieurs threads de se courser pour créer un objet de manière différée. Plusieurs threads peuvent réussir à créer des instances, mais tous les threads utilisent l’instance créée en premier. En outre, l’exemple montre que les exceptions ne sont jamais mises en cache lorsque vous spécifiez LazyThreadSafetyMode.PublicationOnly, même si l’initialisation est effectuée par une fonction plutôt que par le constructeur sans paramètre du type créé parzily.
Note
Pour obtenir un exemple qui montre comment utiliser ce constructeur dans des scénarios à thread unique (en spécifiant LazyThreadSafetyMode.None pour mode
), consultez le constructeur Lazy<T>(Boolean). Pour obtenir un exemple qui montre comment utiliser ce constructeur pour fournir un verrouillage au lieu de conditions de concurrence dans des scénarios multithreads (en spécifiant LazyThreadSafetyMode.ExecutionAndPublication pour mode
), consultez le constructeur Lazy<T>().
L’exemple définit une classe LargeObject
qui sera initialisée de manière différée par l’un des plusieurs threads. Les quatre sections clés du code illustrent la création de l’initialiseur, l’initialisation réelle, la fonction d’initialisation et le constructeur et le finaliseur de la classe LargeObject
. Au début de la méthode Main
, l’exemple crée l’objet Lazy<T> qui effectue une initialisation différée du LargeObject
:
lazyLargeObject = new Lazy<LargeObject>(InitLargeObject,
LazyThreadSafetyMode.PublicationOnly);
let lazyLargeObject = Lazy<LargeObject>(initLargeObject, LazyThreadSafetyMode.PublicationOnly)
lazyLargeObject = New Lazy(Of LargeObject)(AddressOf InitLargeObject, _
LazyThreadSafetyMode.PublicationOnly)
L’initialiseur différé utilise une fonction pour effectuer l’initialisation. Dans ce cas, une fonction est requise, car il n’existe aucun constructeur sans paramètre pour la classe LargeObject
.
L’exemple crée et démarre trois threads qui bloquent sur un objet ManualResetEvent, afin que l’exemple puisse libérer tous les threads en même temps. Dans la méthode ThreadProc
utilisée par les trois threads, l’appel de la propriété Value crée l’instance LargeObject
:
LargeObject large = null;
try
{
large = lazyLargeObject.Value;
// The following line introduces an artificial delay to exaggerate the race condition.
Thread.Sleep(5);
// IMPORTANT: Lazy initialization is thread-safe, but it doesn't protect the
// object after creation. You must lock the object before accessing it,
// unless the type is thread safe. (LargeObject is not thread safe.)
lock(large)
{
large.Data[0] = Thread.CurrentThread.ManagedThreadId;
Console.WriteLine("LargeObject was initialized by thread {0}; last used by thread {1}.",
large.InitializedBy, large.Data[0]);
}
}
catch (ApplicationException ex)
{
Console.WriteLine("ApplicationException: {0}", ex.Message);
}
try
let large = lazyLargeObject.Value
// The following line introduces an artificial delay to exaggerate the race condition.
Thread.Sleep 5
// IMPORTANT: Lazy initialization is thread-safe, but it doesn't protect the
// object after creation. You must lock the object before accessing it,
// unless the type is thread safe. (LargeObject is not thread safe.)
lock large (fun () ->
large.Data[0] <- Thread.CurrentThread.ManagedThreadId
printfn $"LargeObject was initialized by thread {large.InitializedBy} last used by thread {large.Data[0]}.")
with :? ApplicationException as ex ->
printfn $"ApplicationException: {ex.Message}"
Dim large As LargeObject = Nothing
Try
large = lazyLargeObject.Value
' The following line introduces an artificial delay to exaggerate the race condition.
Thread.Sleep(5)
' IMPORTANT: Lazy initialization is thread-safe, but it doesn't protect the
' object after creation. You must lock the object before accessing it,
' unless the type is thread safe. (LargeObject is not thread safe.)
SyncLock large
large.Data(0) = Thread.CurrentThread.ManagedThreadId
Console.WriteLine( _
"LargeObject was initialized by thread {0}; last used by thread {1}.", _
large.InitializedBy, large.Data(0))
End SyncLock
Catch ex As ApplicationException
Console.WriteLine("ApplicationException: {0}", ex.Message)
End Try
Dans la troisième section clé du code, la fonction d’initialisation différée est appelée pour créer l’instance LargeObject
. La fonction lève une exception la première fois qu’elle est appelée :
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
Avec tout autre paramètre de LazyThreadSafetyMode, une exception non gérée dans la fonction d’initialisation est mise en cache. Toutefois, LazyThreadSafetyMode.PublicationOnly supprime la mise en cache des exceptions. La sortie de l’exemple montre qu’une tentative d’initialisation de l’objet réussit.
Note
Le message d’exception apparaît généralement après les messages indiquant que d’autres threads ont correctement initialisé l’objet. Cela est dû au délai introduit par la levée et l’interception de l’exception.
Étant donné que le constructeur de l’instance Lazy<T> spécifiée LazyThreadSafetyMode.PublicationOnly, les trois threads sont autorisés à créer des instances LargeObject
. L’exemple illustre cela en affichant les messages de console dans le constructeur et dans le finaliseur de la classe LargeObject
:
public LargeObject(int initializedBy)
{
initBy = initializedBy;
Console.WriteLine("Constructor: Instance initializing on thread {0}", initBy);
}
~LargeObject()
{
Console.WriteLine("Finalizer: Instance was initialized on {0}", initBy);
}
type LargeObject(initBy) =
do
printfn $"Constructor: Instance initializing on thread {initBy}"
override _.Finalize() =
printfn $"Finalizer: Instance was initialized on {initBy}"
Public Sub New(ByVal initializedBy As Integer)
initBy = initializedBy
Console.WriteLine("Constructor: Instance initializing on thread {0}", initBy)
End Sub
Protected Overrides Sub Finalize()
Console.WriteLine("Finalizer: Instance was initialized on {0}", initBy)
End Sub
L’objet Lazy<T> garantit qu’une seule instance est utilisée par tous les threads (à l’exception du thread où la fonction d’initialisation lève une exception). La sortie de l’exemple montre ceci.
Note
Par souci de simplicité, cet exemple utilise une instance globale de Lazy<T>, et toutes les méthodes sont static
(Shared
en Visual Basic). Ces conditions ne sont pas requises pour l’utilisation de l’initialisation différée.
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
'
Remarques
Le mode de sécurité de thread d’une instance de Lazy<T> décrit le comportement lorsque plusieurs threads essaient d’initialiser l’instance Lazy<T>.
Les exceptions levées par valueFactory
sont mises en cache, sauf si mode
est LazyThreadSafetyMode.PublicationOnly. Pour plus d’informations, consultez la classe Lazy<T> ou l’énumération System.Threading.LazyThreadSafetyMode.