Lazy<T> Construtores
Definição
Importante
Algumas informações se referem a produtos de pré-lançamento que podem ser substancialmente modificados antes do lançamento. A Microsoft não oferece garantias, expressas ou implícitas, das informações aqui fornecidas.
Inicializa uma nova instância da classe Lazy<T>.
Sobrecargas
Lazy<T>() |
Inicializa uma nova instância da classe Lazy<T>. Quando ocorre uma inicialização lenta, o construtor sem parâmetros do tipo de destino é usado. |
Lazy<T>(Boolean) |
Inicializa uma nova instância da classe Lazy<T>. Quando ocorre uma inicialização lenta, o construtor sem parâmetros do tipo de destino e o modo de inicialização especificado são usados. |
Lazy<T>(Func<T>) |
Inicializa uma nova instância da classe Lazy<T>. Quando ocorre uma inicialização lenta, a função de inicialização especificada é usada. |
Lazy<T>(LazyThreadSafetyMode) |
Inicializa uma nova instância da classe Lazy<T> que usa o construtor sem parâmetros de |
Lazy<T>(T) |
Inicializa uma nova instância da classe Lazy<T> que usa um valor especificado pré-inicializado. |
Lazy<T>(Func<T>, Boolean) |
Inicializa uma nova instância da classe Lazy<T>. Quando ocorre uma inicialização lenta, a função de inicialização especificada e o modo de inicialização são usados. |
Lazy<T>(Func<T>, LazyThreadSafetyMode) |
Inicializa uma nova instância da classe Lazy<T> que usa a função de inicialização especificada e o modo de segurança de thread. |
Lazy<T>()
- Origem:
- Lazy.cs
- Origem:
- Lazy.cs
- Origem:
- Lazy.cs
Inicializa uma nova instância da classe Lazy<T>. Quando ocorre uma inicialização lenta, o construtor sem parâmetros do tipo de destino é usado.
public:
Lazy();
public Lazy ();
Public Sub New ()
Exemplos
O exemplo a seguir demonstra o uso desse construtor. Ele também ilustra o uso do construtor Lazy<T>(Boolean) (especificando true
para isThreadSafe
) e do construtor Lazy<T>(LazyThreadSafetyMode) (especificando LazyThreadSafetyMode.ExecutionAndPublication para mode
). Para alternar para um construtor diferente, basta alterar quais construtores são comentados.
O exemplo define uma classe LargeObject
que será inicializada de forma preguiçosa por um dos vários threads. As duas principais linhas de código neste exemplo são a criação do inicializador e a inicialização real. No início do método Main
, o exemplo cria o inicializador lento de thread-safe para 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)
O exemplo cria e inicia três threads que bloqueiam em um objeto ManualResetEvent, para que o exemplo possa liberar os threads de uma só vez. O método ThreadProc
usado pelos três threads chama a propriedade Value para obter a instância de LargeObject
:
LargeObject large = lazyLargeObject.Value;
let large = lazyLargeObject.Value
Dim large As LargeObject = lazyLargeObject.Value
A classe Lazy<T> fornece bloqueio, de modo que apenas um thread tenha permissão para criar a instância LargeObject
. O exemplo demonstra que todos os outros threads obtêm a mesma instância.
Nota
Para simplificar, este exemplo usa uma instância global de Lazy<T>e todos os métodos são static
(Shared
no Visual Basic). Esses não são requisitos para o uso da inicialização lenta.
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
Comentários
Uma instância criada com esse construtor pode ser usada simultaneamente de vários threads.
O modo de segurança de thread de uma instância de Lazy<T> inicializada com esse construtor é LazyThreadSafetyMode.ExecutionAndPublication. O modo de segurança de thread descreve o comportamento quando vários threads tentam inicializar a instância de Lazy<T>.
Uma instância de Lazy<T> criada com esse construtor não armazena exceções em cache. Para obter mais informações, consulte a classe Lazy<T> ou a enumeração System.Threading.LazyThreadSafetyMode.
Confira também
Aplica-se a
Lazy<T>(Boolean)
- Origem:
- Lazy.cs
- Origem:
- Lazy.cs
- Origem:
- Lazy.cs
Inicializa uma nova instância da classe Lazy<T>. Quando ocorre uma inicialização lenta, o construtor sem parâmetros do tipo de destino e o modo de inicialização especificado são usados.
public:
Lazy(bool isThreadSafe);
public Lazy (bool isThreadSafe);
new Lazy<'T> : bool -> Lazy<'T>
Public Sub New (isThreadSafe As Boolean)
Parâmetros
- isThreadSafe
- Boolean
true
para tornar essa instância utilizável simultaneamente por vários threads; false
para tornar a instância utilizável por apenas um thread de cada vez.
Exemplos
O exemplo a seguir demonstra o uso desse construtor para criar um inicializador lento que não é thread safe, para cenários em que todo o acesso ao objeto inicializado preguiçosamente ocorre no mesmo thread. Ele também demonstra o uso do construtor Lazy<T>(LazyThreadSafetyMode) (especificando LazyThreadSafetyMode.None para mode
. Para alternar para um construtor diferente, basta alterar qual construtor é comentado.
Nota
Para obter um código que demonstra como usar esse construtor em cenários multithreaded (especificando true
para isThreadSafe
), consulte o exemplo do construtor Lazy<T>().
O exemplo define uma classe LargeObject
que será inicializada de forma preguiçosa. No método Main
, o exemplo cria uma instância Lazy<T> e, em seguida, pausa. Quando você pressiona a tecla Enter, o exemplo acessa a propriedade Value da instância Lazy<T>, o que faz com que a inicialização ocorra. O construtor da classe LargeObject
exibe uma mensagem de console.
Nota
Para simplificar, este exemplo usa uma instância global de Lazy<T>e todos os métodos são static
(Shared
no Visual Basic). Esses não são requisitos para o uso da inicialização lenta.
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
Comentários
O modo de segurança de thread de uma instância de Lazy<T> inicializada com esse construtor será LazyThreadSafetyMode.ExecutionAndPublication se isThreadSafe
for true
; caso contrário, o modo é LazyThreadSafetyMode.None. O modo de segurança de thread descreve o comportamento quando vários threads tentam inicializar a instância de Lazy<T>. Para especificar o modo LazyThreadSafetyMode.PublicationOnly, use o construtor Lazy<T>(Func<T>, LazyThreadSafetyMode) ou Lazy<T>(LazyThreadSafetyMode).
Uma instância de Lazy<T> criada com esse construtor não armazena exceções em cache. Para obter mais informações, consulte a classe Lazy<T> ou a enumeração System.Threading.LazyThreadSafetyMode.
Confira também
Aplica-se a
Lazy<T>(Func<T>)
- Origem:
- Lazy.cs
- Origem:
- Lazy.cs
- Origem:
- Lazy.cs
Inicializa uma nova instância da classe Lazy<T>. Quando ocorre uma inicialização lenta, a função de inicialização especificada é usada.
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))
Parâmetros
- valueFactory
- Func<T>
O delegado que é invocado para produzir o valor inicializado preguiçosamente quando necessário.
Exceções
valueFactory
é null
.
Exemplos
O exemplo a seguir demonstra o uso desse construtor para fornecer inicialização lenta com cache de exceção. Ele também demonstra o uso do construtor Lazy<T>(Func<T>, Boolean) (especificando true
para isThreadSafe
) e do construtor Lazy<T>(Func<T>, LazyThreadSafetyMode) (especificando LazyThreadSafetyMode.ExecutionAndPublication para mode
). Para alternar para um construtor diferente, basta alterar quais construtores são comentados.
O exemplo define uma classe LargeObject
que será inicializada de forma preguiçosa por um dos vários threads. As três seções principais do código ilustram a criação do inicializador, a inicialização real e o construtor da classe LargeObject
, que demonstra o cache de exceção. No início do método Main
, o exemplo cria o inicializador lento de thread-safe para 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)
O exemplo cria e inicia três threads. O método ThreadProc
usado pelos três threads chama a propriedade Value para obter a instância de 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
No construtor da classe LargeObject
, a terceira seção chave do código gera uma exceção na primeira vez que uma instância de LargeObject
é criada, mas depois disso permite que a criação da instância ocorra:
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
Quando o exemplo é executado, o primeiro thread que tenta criar uma instância de LargeObject
falha e a exceção é capturada. Você pode esperar que o próximo thread crie uma instância com êxito, mas o objeto Lazy<T> armazenou a exceção em cache. Por causa disso, todos os três threads geram a exceção.
Nota
Para simplificar, este exemplo usa uma instância global de Lazy<T>e todos os métodos são static
(Shared
no Visual Basic). Esses não são requisitos para o uso da inicialização lenta.
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
'
Comentários
Uma instância criada com esse construtor pode ser usada simultaneamente de vários threads.
O modo de segurança de thread de uma instância de Lazy<T> inicializada com esse construtor é LazyThreadSafetyMode.ExecutionAndPublication. O modo de segurança de thread descreve o comportamento quando vários threads tentam inicializar a instância de Lazy<T>.
Exceções geradas por valueFactory
são armazenadas em cache. Para obter mais informações, consulte a classe Lazy<T> ou a enumeração System.Threading.LazyThreadSafetyMode.
Confira também
Aplica-se a
Lazy<T>(LazyThreadSafetyMode)
- Origem:
- Lazy.cs
- Origem:
- Lazy.cs
- Origem:
- Lazy.cs
Inicializa uma nova instância da classe Lazy<T> que usa o construtor sem parâmetros de T
e o modo de segurança de thread especificado.
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)
Parâmetros
- mode
- LazyThreadSafetyMode
Um dos valores de enumeração que especifica o modo de segurança de thread.
Exceções
mode
contém um valor inválido.
Exemplos
O exemplo a seguir demonstra o uso desse construtor para criar um inicializador lento que permite a corrida de vários threads para criar um objeto de forma preguiçosa. Vários threads podem ter êxito na criação de instâncias, mas todos os threads usam a instância que foi criada primeiro.
Nota
Para obter um exemplo que demonstra como usar esse construtor em cenários de thread único (especificando LazyThreadSafetyMode.None para mode
), consulte o construtor Lazy<T>(Boolean). Para obter um exemplo que demonstra como usar esse construtor para fornecer bloqueio em vez de condições de corrida em cenários multithreaded (especificando LazyThreadSafetyMode.ExecutionAndPublication para mode
), consulte o construtor Lazy<T>().
O exemplo define uma classe LargeObject
que será inicializada de forma preguiçosa por qualquer um dos vários threads. As três seções principais do código ilustram a criação do inicializador, a inicialização real e o construtor e o finalizador da classe LargeObject
. No início do método Main
, o exemplo cria o objeto Lazy<T> que executa a inicialização lenta do LargeObject
:
lazyLargeObject = new Lazy<LargeObject>(LazyThreadSafetyMode.PublicationOnly);
let lazyLargeObject = Lazy<LargeObject> LazyThreadSafetyMode.PublicationOnly
lazyLargeObject = New Lazy(Of LargeObject)(LazyThreadSafetyMode.PublicationOnly)
O exemplo cria e inicia três threads que bloqueiam em um objeto ManualResetEvent, para que o exemplo possa liberar os threads de uma só vez. No método ThreadProc
usado pelos três threads, chamar a propriedade Value cria a instância LargeObject
:
LargeObject large = lazyLargeObject.Value;
let large = lazyLargeObject.Value
Dim large As LargeObject = lazyLargeObject.Value
Como o construtor da instância de Lazy<T> especificada LazyThreadSafetyMode.PublicationOnly, todos os três threads têm permissão para criar LargeObject
instâncias. O exemplo demonstra isso exibindo mensagens de console no construtor e no finalizador da 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
No entanto, o objeto Lazy<T> garante que apenas uma instância seja usada por todos os threads. A saída do exemplo mostra que todos os três threads usam a mesma instância e também mostra que as outras duas instâncias podem ser recuperadas pela coleta de lixo.
Nota
Para simplificar, este exemplo usa uma instância global de Lazy<T>e todos os métodos são static
(Shared
no Visual Basic). Esses não são requisitos para o uso da inicialização lenta.
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
'
Comentários
O modo de segurança de thread de uma instância de Lazy<T> descreve o comportamento quando vários threads tentam inicializar a instância de Lazy<T>.
Uma instância de Lazy<T> criada com esse construtor não armazena exceções em cache. Para obter mais informações, consulte a classe Lazy<T> ou a enumeração System.Threading.LazyThreadSafetyMode.
Confira também
- LazyThreadSafetyMode
- de inicialização lenta
Aplica-se a
Lazy<T>(T)
- Origem:
- Lazy.cs
- Origem:
- Lazy.cs
- Origem:
- Lazy.cs
Inicializa uma nova instância da classe Lazy<T> que usa um valor especificado pré-inicializado.
public:
Lazy(T value);
public Lazy (T value);
new Lazy<'T> : 'T -> Lazy<'T>
Public Sub New (value As T)
Parâmetros
- value
- T
O valor pré-inicializado a ser usado.
Comentários
Uma instância criada com esse construtor é utilizável por vários threads simultaneamente.
Aplica-se a
Lazy<T>(Func<T>, Boolean)
- Origem:
- Lazy.cs
- Origem:
- Lazy.cs
- Origem:
- Lazy.cs
Inicializa uma nova instância da classe Lazy<T>. Quando ocorre uma inicialização lenta, a função de inicialização especificada e o modo de inicialização são usados.
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)
Parâmetros
- valueFactory
- Func<T>
O delegado que é invocado para produzir o valor inicializado preguiçosamente quando necessário.
- isThreadSafe
- Boolean
true
para tornar essa instância utilizável simultaneamente por vários threads; false
para tornar essa instância utilizável por apenas um thread de cada vez.
Exceções
valueFactory
é null
.
Exemplos
O exemplo a seguir demonstra o uso desse construtor para fornecer inicialização lenta com cache de exceção, em um cenário com um único thread. Ele também demonstra o uso do construtor Lazy<T> (especificando LazyThreadSafetyMode.None para mode
). Para alternar para esse construtor, basta alterar qual construtor é comentado.
Nota
Para obter um código que demonstra como usar esse construtor em cenários multithreaded (especificando true
para isThreadSafe
), consulte o exemplo do construtor Lazy<T>(Func<T>).
O exemplo define uma classe LargeObject
que será inicializada de forma preguiçosa por um dos vários threads. As três seções principais do código ilustram a criação do inicializador, a inicialização real e o construtor da classe LargeObject
, que demonstra o cache de exceção. No início do método Main
, o exemplo cria o inicializador lento de thread-safe para 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)
Na chamada para o construtor, o parâmetro isThreadSafe
é false
, portanto, o Lazy<T> não é thread-safe. Como não é thread-safe, o exemplo chama a propriedade Value três vezes no mesmo 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
No construtor da classe LargeObject
, a terceira seção chave do código gera uma exceção na primeira vez que uma instância de LargeObject
é criada, mas depois disso permite que a criação da instância ocorra:
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
Quando o exemplo é executado, a primeira tentativa de criar uma instância de LargeObject
falha e a exceção é capturada. Você pode esperar que a próxima tentativa seja bem-sucedida, mas o objeto Lazy<T> armazenou a exceção em cache. Por causa disso, todas as três tentativas geram a exceção.
Nota
Para simplificar, este exemplo usa uma instância global de Lazy<T>e todos os métodos são static
(Shared
no Visual Basic). Esses não são requisitos para o uso da inicialização lenta.
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
'
Comentários
O modo de segurança de thread de uma instância de Lazy<T> inicializada com esse construtor será LazyThreadSafetyMode.ExecutionAndPublication se isThreadSafe
for true
; caso contrário, o modo é LazyThreadSafetyMode.None. O modo de segurança de thread descreve o comportamento quando vários threads tentam inicializar a instância de Lazy<T>.
Para especificar o modo LazyThreadSafetyMode.PublicationOnly, use o construtor Lazy<T>(Func<T>, LazyThreadSafetyMode) ou Lazy<T>(LazyThreadSafetyMode).
Exceções geradas por valueFactory
são armazenadas em cache. Para obter mais informações, consulte a classe Lazy<T> ou a enumeração System.Threading.LazyThreadSafetyMode.
Confira também
Aplica-se a
Lazy<T>(Func<T>, LazyThreadSafetyMode)
- Origem:
- Lazy.cs
- Origem:
- Lazy.cs
- Origem:
- Lazy.cs
Inicializa uma nova instância da classe Lazy<T> que usa a função de inicialização especificada e o modo de segurança de thread.
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)
Parâmetros
- valueFactory
- Func<T>
O delegado que é invocado para produzir o valor inicializado preguiçosamente quando necessário.
- mode
- LazyThreadSafetyMode
Um dos valores de enumeração que especifica o modo de segurança de thread.
Exceções
mode
contém um valor inválido.
valueFactory
é null
.
Exemplos
O exemplo a seguir demonstra o uso desse construtor para criar um inicializador lento que permite a corrida de vários threads para criar um objeto de forma preguiçosa. Vários threads podem ter êxito na criação de instâncias, mas todos os threads usam a instância que foi criada primeiro. Além disso, o exemplo demonstra que as exceções nunca são armazenadas em cache quando você especifica LazyThreadSafetyMode.PublicationOnly, mesmo que a inicialização seja executada por uma função em vez de pelo construtor sem parâmetros do tipo criado preguiçosamente.
Nota
Para obter um exemplo que demonstra como usar esse construtor em cenários de thread único (especificando LazyThreadSafetyMode.None para mode
), consulte o construtor Lazy<T>(Boolean). Para obter um exemplo que demonstra como usar esse construtor para fornecer bloqueio em vez de condições de corrida em cenários multithreaded (especificando LazyThreadSafetyMode.ExecutionAndPublication para mode
), consulte o construtor Lazy<T>().
O exemplo define uma classe LargeObject
que será inicializada de forma preguiçosa por qualquer um dos vários threads. As quatro seções principais do código ilustram a criação do inicializador, a inicialização real, a função de inicialização e o construtor e o finalizador da classe LargeObject
. No início do método Main
, o exemplo cria o objeto Lazy<T> que executa a inicialização lenta do LargeObject
:
lazyLargeObject = new Lazy<LargeObject>(InitLargeObject,
LazyThreadSafetyMode.PublicationOnly);
let lazyLargeObject = Lazy<LargeObject>(initLargeObject, LazyThreadSafetyMode.PublicationOnly)
lazyLargeObject = New Lazy(Of LargeObject)(AddressOf InitLargeObject, _
LazyThreadSafetyMode.PublicationOnly)
O inicializador lento usa uma função para executar a inicialização. Nesse caso, uma função é necessária porque não há construtor sem parâmetros para a classe LargeObject
.
O exemplo cria e inicia três threads que bloqueiam em um objeto ManualResetEvent, para que o exemplo possa liberar os threads de uma só vez. No método ThreadProc
usado pelos três threads, chamar a propriedade Value cria a instância 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
Na terceira seção chave do código, a função de inicialização lenta é chamada para criar a instância de LargeObject
. A função gera uma exceção na primeira vez que é chamada:
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
Com qualquer outra configuração de LazyThreadSafetyMode, uma exceção sem tratamento na função de inicialização seria armazenada em cache. No entanto, LazyThreadSafetyMode.PublicationOnly suprime o cache de exceção. A saída do exemplo demonstra que uma tentativa subsequente de inicializar o objeto é bem-sucedida.
Nota
A mensagem de exceção geralmente aparece após mensagens indicando que outros threads inicializaram o objeto com êxito. Isso ocorre devido ao atraso introduzido lançando e capturando a exceção.
Como o construtor da instância de Lazy<T> especificada LazyThreadSafetyMode.PublicationOnly, todos os três threads têm permissão para criar LargeObject
instâncias. O exemplo demonstra isso exibindo mensagens de console no construtor e no finalizador da 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
O objeto Lazy<T> garante que apenas uma instância seja usada por todos os threads (exceto o thread em que a função de inicialização gera uma exceção). A saída do exemplo mostra isso.
Nota
Para simplificar, este exemplo usa uma instância global de Lazy<T>e todos os métodos são static
(Shared
no Visual Basic). Esses não são requisitos para o uso da inicialização lenta.
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
'
Comentários
O modo de segurança de thread de uma instância de Lazy<T> descreve o comportamento quando vários threads tentam inicializar a instância de Lazy<T>.
Exceções geradas por valueFactory
são armazenadas em cache, a menos que mode
seja LazyThreadSafetyMode.PublicationOnly. Para obter mais informações, consulte a classe Lazy<T> ou a enumeração System.Threading.LazyThreadSafetyMode.