Lazy<T> コンストラクター
定義
重要
一部の情報は、リリース前に大きく変更される可能性があるプレリリースされた製品に関するものです。 Microsoft は、ここに記載されている情報について、明示または黙示を問わず、一切保証しません。
Lazy<T> クラスの新しいインスタンスを初期化します。
オーバーロード
Lazy<T>() |
Lazy<T> クラスの新しいインスタンスを初期化します。 遅延初期化が発生すると、ターゲット型のパラメーターなしのコンストラクターが使用されます。 |
Lazy<T>(Boolean) |
Lazy<T> クラスの新しいインスタンスを初期化します。 遅延初期化が発生すると、ターゲット型のパラメーターなしのコンストラクターと、指定された初期化モードが使用されます。 |
Lazy<T>(Func<T>) |
Lazy<T> クラスの新しいインスタンスを初期化します。 遅延初期化が発生すると、指定された初期化関数が使用されます。 |
Lazy<T>(LazyThreadSafetyMode) |
|
Lazy<T>(T) |
事前に初期化された指定した値を使用する Lazy<T> クラスの新しいインスタンスを初期化します。 |
Lazy<T>(Func<T>, Boolean) |
Lazy<T> クラスの新しいインスタンスを初期化します。 遅延初期化が発生すると、指定された初期化関数と初期化モードが使用されます。 |
Lazy<T>(Func<T>, LazyThreadSafetyMode) |
指定した初期化関数とスレッド セーフ モードを使用する Lazy<T> クラスの新しいインスタンスを初期化します。 |
Lazy<T>()
- ソース:
- Lazy.cs
- ソース:
- Lazy.cs
- ソース:
- Lazy.cs
Lazy<T> クラスの新しいインスタンスを初期化します。 遅延初期化が発生すると、ターゲット型のパラメーターなしのコンストラクターが使用されます。
public:
Lazy();
public Lazy ();
Public Sub New ()
例
次の例では、このコンストラクターの使用方法を示します。 また、Lazy<T>(Boolean) コンストラクター (isThreadSafe
に true
を指定する) と Lazy<T>(LazyThreadSafetyMode) コンストラクター (mode
に LazyThreadSafetyMode.ExecutionAndPublication を指定する) の使用方法についても説明します。 別のコンストラクターに切り替えるには、コメント アウトするコンストラクターを変更するだけです。
この例では、複数のスレッドの 1 つによって遅延的に初期化される LargeObject
クラスを定義します。 この例のコードの 2 つの重要な行は、初期化子の作成と実際の初期化です。 この例では、Main
メソッドの先頭に、LargeObject
のスレッド セーフな遅延初期化子を作成します。
lazyLargeObject = new Lazy<LargeObject>();
// The following lines show how to use other constructors to achieve exactly the
// same result as the previous line:
//lazyLargeObject = new Lazy<LargeObject>(true);
//lazyLargeObject = new Lazy<LargeObject>(LazyThreadSafetyMode.ExecutionAndPublication);
let lazyLargeObject = Lazy<LargeObject>()
// The following lines show how to use other constructors to achieve exactly the
// same result as the previous line:
// let lazyLargeObject = Lazy<LargeObject>(true)
// let lazyLargeObject = Lazy<LargeObject>(LazyThreadSafetyMode.ExecutionAndPublication)
lazyLargeObject = New Lazy(Of LargeObject)()
' The following lines show how to use other constructors to achieve exactly the
' same result as the previous line:
'lazyLargeObject = New Lazy(Of LargeObject)(True)
'lazyLargeObject = New Lazy(Of LargeObject)(LazyThreadSafetyMode.ExecutionAndPublication)
この例では、ManualResetEvent オブジェクトでブロックする 3 つのスレッドを作成して開始します。この例では、スレッドをすべて一度に解放できます。 3 つのスレッドすべてで使用される ThreadProc
メソッドは、Value プロパティを呼び出して、LargeObject
インスタンスを取得します。
LargeObject large = lazyLargeObject.Value;
let large = lazyLargeObject.Value
Dim large As LargeObject = lazyLargeObject.Value
Lazy<T> クラスはロックを提供するため、LargeObject
インスタンスの作成が許可されるスレッドは 1 つだけです。 この例では、他のスレッドがすべて同じインスタンスを取得することを示しています。
手記
わかりやすくするために、この例では Lazy<T>のグローバル インスタンスを使用し、すべてのメソッドが static
されます (Visual Basic ではShared
)。 これらは、遅延初期化を使用するための要件ではありません。
using System;
using System.Threading;
class Program
{
static Lazy<LargeObject> lazyLargeObject = null;
static void Main()
{
// The lazy initializer is created here. LargeObject is not created until the
// ThreadProc method executes.
lazyLargeObject = new Lazy<LargeObject>();
// The following lines show how to use other constructors to achieve exactly the
// same result as the previous line:
//lazyLargeObject = new Lazy<LargeObject>(true);
//lazyLargeObject = new Lazy<LargeObject>(LazyThreadSafetyMode.ExecutionAndPublication);
Console.WriteLine(
"\r\nLargeObject is not created until you access the Value property of the lazy" +
"\r\ninitializer. Press Enter to create LargeObject.");
Console.ReadLine();
// Create and start 3 threads, passing the same blocking event to all of them.
ManualResetEvent startingGate = new ManualResetEvent(false);
Thread[] threads = { new Thread(ThreadProc), new Thread(ThreadProc), new Thread(ThreadProc) };
foreach (Thread t in threads)
{
t.Start(startingGate);
}
// Give all 3 threads time to start and wait, then release them all at once.
Thread.Sleep(100);
startingGate.Set();
// Wait for all 3 threads to finish. (The order doesn't matter.)
foreach (Thread t in threads)
{
t.Join();
}
Console.WriteLine("\r\nPress Enter to end the program");
Console.ReadLine();
}
static void ThreadProc(object state)
{
// Wait for the signal.
ManualResetEvent waitForStart = (ManualResetEvent) state;
waitForStart.WaitOne();
LargeObject large = lazyLargeObject.Value;
// The following line introduces an artificial delay to exaggerate the race condition.
Thread.Sleep(5);
// IMPORTANT: Lazy initialization is thread-safe, but it doesn't protect the
// object after creation. You must lock the object before accessing it,
// unless the type is thread safe. (LargeObject is not thread safe.)
lock(large)
{
large.Data[0] = Thread.CurrentThread.ManagedThreadId;
Console.WriteLine("Initialized by thread {0}; last used by thread {1}.",
large.InitializedBy, large.Data[0]);
}
}
}
class LargeObject
{
int initBy = 0;
public int InitializedBy { get { return initBy; } }
public LargeObject()
{
initBy = Thread.CurrentThread.ManagedThreadId;
Console.WriteLine("LargeObject was created on thread id {0}.", initBy);
}
public long[] Data = new long[100000000];
}
/* This example produces output similar to the following:
LargeObject is not created until you access the Value property of the lazy
initializer. Press Enter to create LargeObject.
LargeObject was created on thread id 4.
Initialized by thread 4; last used by thread 3.
Initialized by thread 4; last used by thread 4.
Initialized by thread 4; last used by thread 5.
Press Enter to end the program
*/
open System
open System.Threading
type LargeObject() =
let initBy = Thread.CurrentThread.ManagedThreadId
do
printfn $"LargeObject was created on thread id {initBy}."
member val Data = Array.zeroCreate<int64> 100000000 with get
member _.InitializedBy = initBy
// The lazy initializer is created here. LargeObject is not created until the
// ThreadProc method executes.
let lazyLargeObject = Lazy<LargeObject>()
// The following lines show how to use other constructors to achieve exactly the
// same result as the previous line:
// let lazyLargeObject = Lazy<LargeObject>(true)
// let lazyLargeObject = Lazy<LargeObject>(LazyThreadSafetyMode.ExecutionAndPublication)
let threadProc (state: obj) =
// Wait for the signal.
let waitForStart = state :?> ManualResetEvent
waitForStart.WaitOne() |> ignore
let large = lazyLargeObject.Value
// The following line introduces an artificial delay to exaggerate the race condition.
Thread.Sleep 5
// IMPORTANT: Lazy initialization is thread-safe, but it doesn't protect the
// object after creation. You must lock the object before accessing it,
// unless the type is thread safe. (LargeObject is not thread safe.)
lock large (fun () ->
large.Data[0] <- Thread.CurrentThread.ManagedThreadId
printfn $"Initialized by thread {large.InitializedBy} last used by thread {large.Data[0]}." )
printfn """
LargeObject is not created until you access the Value property of the lazy
initializer. Press Enter to create LargeObject."""
stdin.ReadLine() |> ignore
// Create and start 3 threads, passing the same blocking event to all of them.
let startingGate = new ManualResetEvent false
let threads = [| Thread(ParameterizedThreadStart threadProc); Thread(ParameterizedThreadStart threadProc); Thread(ParameterizedThreadStart threadProc) |]
for t in threads do
t.Start startingGate
// Give all 3 threads time to start and wait, then release them all at once.
Thread.Sleep 100
startingGate.Set() |> ignore
// Wait for all 3 threads to finish. (The order doesn't matter.)
for t in threads do
t.Join()
printfn "\nPress Enter to end the program"
stdin.ReadLine() |> ignore
// This example produces output similar to the following:
// LargeObject is not created until you access the Value property of the lazy
// initializer. Press Enter to create LargeObject.
//
// LargeObject was created on thread id 4.
// Initialized by thread 4 last used by thread 3.
// Initialized by thread 4 last used by thread 4.
// Initialized by thread 4 last used by thread 5.
//
// Press Enter to end the program
Imports System.Threading
Class Program
Private Shared lazyLargeObject As Lazy(Of LargeObject) = Nothing
Shared Sub Main()
' The lazy initializer is created here. LargeObject is not created until the
' ThreadProc method executes.
lazyLargeObject = New Lazy(Of LargeObject)()
' The following lines show how to use other constructors to achieve exactly the
' same result as the previous line:
'lazyLargeObject = New Lazy(Of LargeObject)(True)
'lazyLargeObject = New Lazy(Of LargeObject)(LazyThreadSafetyMode.ExecutionAndPublication)
Console.WriteLine( _
vbCrLf & "LargeObject is not created until you access the Value property of the lazy" _
& vbCrLf & "initializer. Press Enter to create LargeObject.")
Console.ReadLine()
' Create and start 3 threads, passing the same blocking event to all of them.
Dim startingGate As New ManualResetEvent(False)
Dim threads() As Thread = { New Thread(AddressOf ThreadProc),
New Thread(AddressOf ThreadProc), New Thread(AddressOf ThreadProc) }
For Each t As Thread In threads
t.Start(startingGate)
Next t
' Give all 3 threads time to start and wait, then release them all at once.
Thread.Sleep(100)
startingGate.Set()
' Wait for all 3 threads to finish. (The order doesn't matter.)
For Each t As Thread In threads
t.Join()
Next t
Console.WriteLine(vbCrLf & "Press Enter to end the program")
Console.ReadLine()
End Sub
Private Shared Sub ThreadProc(ByVal state As Object)
' Wait for the signal.
Dim waitForStart As ManualResetEvent = CType(state, ManualResetEvent)
waitForStart.WaitOne()
Dim large As LargeObject = lazyLargeObject.Value
' The following line introduces an artificial delay to exaggerate the race condition.
Thread.Sleep(5)
' IMPORTANT: Lazy initialization is thread-safe, but it doesn't protect the
' object after creation. You must lock the object before accessing it,
' unless the type is thread safe. (LargeObject is not thread safe.)
SyncLock large
large.Data(0) = Thread.CurrentThread.ManagedThreadId
Console.WriteLine("Initialized by thread {0}; last used by thread {1}.", _
large.InitializedBy, large.Data(0))
End SyncLock
End Sub
End Class
Class LargeObject
Private initBy As Integer = 0
Public ReadOnly Property InitializedBy() As Integer
Get
Return initBy
End Get
End Property
Public Sub New()
initBy = Thread.CurrentThread.ManagedThreadId
Console.WriteLine("LargeObject was created on thread id {0}.", initBy)
End Sub
Public Data(100000000) As Long
End Class
' This example produces output similar to the following:
'
'LargeObject is not created until you access the Value property of the lazy
'initializer. Press Enter to create LargeObject.
'
'LargeObject was created on thread id 3.
'Initialized by thread 3; last used by thread 5.
'Initialized by thread 3; last used by thread 4.
'Initialized by thread 3; last used by thread 3.
'
'Press Enter to end the program
注釈
このコンストラクターで作成されたインスタンスは、複数のスレッドから同時に使用できます。
このコンストラクターで初期化される Lazy<T> インスタンスのスレッド セーフ モードは LazyThreadSafetyMode.ExecutionAndPublication。 スレッド セーフ モードは、複数のスレッドが Lazy<T> インスタンスを初期化しようとしたときの動作を表します。
このコンストラクターで作成された Lazy<T> インスタンスは、例外をキャッシュしません。 詳細については、Lazy<T> クラスまたは System.Threading.LazyThreadSafetyMode 列挙体を参照してください。
こちらもご覧ください
- 遅延初期化 の
適用対象
Lazy<T>(Boolean)
- ソース:
- Lazy.cs
- ソース:
- Lazy.cs
- ソース:
- Lazy.cs
Lazy<T> クラスの新しいインスタンスを初期化します。 遅延初期化が発生すると、ターゲット型のパラメーターなしのコンストラクターと、指定された初期化モードが使用されます。
public:
Lazy(bool isThreadSafe);
public Lazy (bool isThreadSafe);
new Lazy<'T> : bool -> Lazy<'T>
Public Sub New (isThreadSafe As Boolean)
パラメーター
- isThreadSafe
- Boolean
このインスタンスを複数のスレッドで同時に使用できるようにする true
。false
、インスタンスを一度に 1 つのスレッドでのみ使用できるようにします。
例
次の例では、このコンストラクターを使用して、遅延初期化オブジェクトへのすべてのアクセスが同じスレッドで行われるシナリオで、スレッド セーフではない遅延初期化子を作成する方法を示します。 また、Lazy<T>(LazyThreadSafetyMode) コンストラクター (mode
の LazyThreadSafetyMode.None を指定する) の使用方法も示します。 別のコンストラクターに切り替えるには、コメント アウトするコンストラクターを変更するだけです。
手記
マルチスレッド シナリオでこのコンストラクターを使用する方法を示すコード (isThreadSafe
の true
を指定) については、Lazy<T>() コンストラクターの例を参照してください。
この例では、遅延初期化される LargeObject
クラスを定義します。
Main
メソッドでは、Lazy<T> インスタンスを作成し、一時停止します。
Enter キーを押すと、Lazy<T> インスタンスの Value プロパティにアクセスし、初期化が発生します。
LargeObject
クラスのコンストラクターは、コンソール メッセージを表示します。
手記
わかりやすくするために、この例では Lazy<T>のグローバル インスタンスを使用し、すべてのメソッドが static
されます (Visual Basic ではShared
)。 これらは、遅延初期化を使用するための要件ではありません。
using System;
using System.Threading;
class Program
{
static Lazy<LargeObject> lazyLargeObject = null;
static void Main()
{
// The lazy initializer is created here. LargeObject is not created until the
// ThreadProc method executes.
lazyLargeObject = new Lazy<LargeObject>(false);
// The following lines show how to use other constructors to achieve exactly the
// same result as the previous line:
//lazyLargeObject = new Lazy<LargeObject>(LazyThreadSafetyMode.None);
Console.WriteLine(
"\r\nLargeObject is not created until you access the Value property of the lazy" +
"\r\ninitializer. Press Enter to create LargeObject.");
Console.ReadLine();
LargeObject large = lazyLargeObject.Value;
large.Data[11] = 89;
Console.WriteLine("\r\nPress Enter to end the program");
Console.ReadLine();
}
}
class LargeObject
{
public LargeObject()
{
Console.WriteLine("LargeObject was created on thread id {0}.",
Thread.CurrentThread.ManagedThreadId);
}
public long[] Data = new long[100000000];
}
/* This example produces output similar to the following:
LargeObject is not created until you access the Value property of the lazy
initializer. Press Enter to create LargeObject.
LargeObject was created on thread id 1.
Press Enter to end the program
*/
open System
open System.Threading
type LargeObject () =
do
printfn $"LargeObject was created on thread id {Thread.CurrentThread.ManagedThreadId}."
member val Data = Array.zeroCreate<int64> 100000000 with get
// The lazy initializer is created here. LargeObject is not created until the
// ThreadProc method executes.
let lazyLargeObject = Lazy<LargeObject> false
// The following lines show how to use other constructors to achieve exactly the
// same result as the previous line:
// let lazyLargeObject = Lazy<LargeObject>(LazyThreadSafetyMode.None)
printfn """
LargeObject is not created until you access the Value property of the lazy
initializer. Press Enter to create LargeObject."""
stdin.ReadLine() |> ignore
let large = lazyLargeObject.Value
large.Data[11] <- 89
printfn "\nPress Enter to end the program"
stdin.ReadLine() |> ignore
// This example produces output similar to the following:
// LargeObject is not created until you access the Value property of the lazy
// initializer. Press Enter to create LargeObject.
//
// LargeObject was created on thread id 1.
//
// Press Enter to end the program
Imports System.Threading
Friend Class Program
Private Shared lazyLargeObject As Lazy(Of LargeObject) = Nothing
Shared Sub Main()
' The lazy initializer is created here. LargeObject is not created until the
' ThreadProc method executes.
lazyLargeObject = New Lazy(Of LargeObject)(False)
' The following lines show how to use other constructors to achieve exactly the
' same result as the previous line:
'lazyLargeObject = new Lazy<LargeObject>(LazyThreadSafetyMode.None);
Console.WriteLine( _
vbCrLf & "LargeObject is not created until you access the Value property of the lazy" _
& vbCrLf & "initializer. Press Enter to create LargeObject.")
Console.ReadLine()
Dim large As LargeObject = lazyLargeObject.Value
large.Data(11) = 89
Console.WriteLine(vbCrLf & "Press Enter to end the program")
Console.ReadLine()
End Sub
End Class
Friend Class LargeObject
Public Sub New()
Console.WriteLine("LargeObject was created on thread id {0}.", _
Thread.CurrentThread.ManagedThreadId)
End Sub
Public Data(100000000) As Long
End Class
' This example produces output similar to the following:
'
'LargeObject is not created until you access the Value property of the lazy
'initializer. Press Enter to create LargeObject.
'
'LargeObject was created on thread id 1.
'
'Press Enter to end the program
注釈
このコンストラクターで初期化される Lazy<T> インスタンスのスレッド セーフ モードは、isThreadSafe
が true
されている場合に LazyThreadSafetyMode.ExecutionAndPublication されます。それ以外の場合、モードは LazyThreadSafetyMode.None。 スレッド セーフ モードは、複数のスレッドが Lazy<T> インスタンスを初期化しようとしたときの動作を表します。
LazyThreadSafetyMode.PublicationOnly モードを指定するには、Lazy<T>(Func<T>, LazyThreadSafetyMode) または Lazy<T>(LazyThreadSafetyMode) コンストラクターを使用します。
このコンストラクターで作成された Lazy<T> インスタンスは、例外をキャッシュしません。 詳細については、Lazy<T> クラスまたは System.Threading.LazyThreadSafetyMode 列挙体を参照してください。
こちらもご覧ください
- 遅延初期化 の
適用対象
Lazy<T>(Func<T>)
- ソース:
- Lazy.cs
- ソース:
- Lazy.cs
- ソース:
- Lazy.cs
Lazy<T> クラスの新しいインスタンスを初期化します。 遅延初期化が発生すると、指定された初期化関数が使用されます。
public:
Lazy(Func<T> ^ valueFactory);
public Lazy (Func<T> valueFactory);
new Lazy<'T> : Func<'T> -> Lazy<'T>
Public Sub New (valueFactory As Func(Of T))
パラメーター
- valueFactory
- Func<T>
必要に応じて遅延初期化値を生成するために呼び出されるデリゲート。
例外
valueFactory
は null
です。
例
次の例では、このコンストラクターを使用して、例外キャッシュを使用して遅延初期化を提供する方法を示します。 また、Lazy<T>(Func<T>, Boolean) コンストラクター (isThreadSafe
に true
を指定する) と Lazy<T>(Func<T>, LazyThreadSafetyMode) コンストラクター (mode
に LazyThreadSafetyMode.ExecutionAndPublication を指定する) の使用方法も示します。 別のコンストラクターに切り替えるには、コメント アウトするコンストラクターを変更するだけです。
この例では、複数のスレッドの 1 つによって遅延的に初期化される LargeObject
クラスを定義します。 コードの 3 つの主要なセクションは、初期化子の作成、実際の初期化、および例外キャッシュを示す LargeObject
クラスのコンストラクターを示しています。 この例では、Main
メソッドの先頭に、LargeObject
のスレッド セーフな遅延初期化子を作成します。
lazyLargeObject = new Lazy<LargeObject>(InitLargeObject);
// The following lines show how to use other constructors to achieve exactly the
// same result as the previous line:
//lazyLargeObject = new Lazy<LargeObject>(InitLargeObject, true);
//lazyLargeObject = new Lazy<LargeObject>(InitLargeObject, LazyThreadSafetyMode.ExecutionAndPublication);
let lazyLargeObject = Lazy<LargeObject> initLargeObject
// The following lines show how to use other constructors to achieve exactly the
// same result as the previous line:
// let lazyLargeObject = Lazy<LargeObject>(initLargeObject, true)
// let lazyLargeObject = Lazy<LargeObject>(initLargeObject, LazyThreadSafetyMode.ExecutionAndPublication)
lazyLargeObject = New Lazy(Of LargeObject)(AddressOf InitLargeObject)
' The following lines show how to use other constructors to achieve exactly the
' same result as the previous line:
'lazyLargeObject = New Lazy(Of LargeObject)(AddressOf InitLargeObject, True)
'lazyLargeObject = New Lazy(Of LargeObject)(AddressOf InitLargeObject, LazyThreadSafetyMode.ExecutionAndPublication)
この例では、3 つのスレッドを作成して開始します。 3 つのスレッドすべてで使用される ThreadProc
メソッドは、Value プロパティを呼び出して、LargeObject
インスタンスを取得します。
try
{
LargeObject large = lazyLargeObject.Value;
// IMPORTANT: Lazy initialization is thread-safe, but it doesn't protect the
// object after creation. You must lock the object before accessing it,
// unless the type is thread safe. (LargeObject is not thread safe.)
lock(large)
{
large.Data[0] = Thread.CurrentThread.ManagedThreadId;
Console.WriteLine("Initialized by thread {0}; last used by thread {1}.",
large.InitializedBy, large.Data[0]);
}
}
catch (ApplicationException aex)
{
Console.WriteLine("Exception: {0}", aex.Message);
}
try
let large = lazyLargeObject.Value
// IMPORTANT: Lazy initialization is thread-safe, but it doesn't protect the
// object after creation. You must lock the object before accessing it,
// unless the type is thread safe. (LargeObject is not thread safe.)
lock large (fun () ->
large.Data[0] <- Thread.CurrentThread.ManagedThreadId
printfn $"Initialized by thread {large.InitializedBy} last used by thread {large.Data[0]}.")
with :? ApplicationException as aex ->
printfn $"Exception: {aex.Message}"
Try
Dim large As LargeObject = lazyLargeObject.Value
' IMPORTANT: Lazy initialization is thread-safe, but it doesn't protect the
' object after creation. You must lock the object before accessing it,
' unless the type is thread safe. (LargeObject is not thread safe.)
SyncLock large
large.Data(0) = Thread.CurrentThread.ManagedThreadId
Console.WriteLine("Initialized by thread {0}; last used by thread {1}.", _
large.InitializedBy, large.Data(0))
End SyncLock
Catch aex As ApplicationException
Console.WriteLine("Exception: {0}", aex.Message)
End Try
LargeObject
クラスのコンストラクターでは、コードの 3 番目のキー セクションでは、LargeObject
インスタンスが初めて作成されるときに例外がスローされますが、その後、インスタンスの作成が可能になります。
static int instanceCount = 0;
public LargeObject()
{
if (1 == Interlocked.Increment(ref instanceCount))
{
throw new ApplicationException("Throw only ONCE.");
}
initBy = Thread.CurrentThread.ManagedThreadId;
Console.WriteLine("LargeObject was created on thread id {0}.", initBy);
}
type LargeObject() =
static let mutable instanceCount = 0
let initBy = Thread.CurrentThread.ManagedThreadId
do
if 1 = Interlocked.Increment &instanceCount then
raise (ApplicationException "Throw only ONCE.")
printfn $"LargeObject was created on thread id {initBy}."
Private Shared instanceCount As Integer = 0
Public Sub New()
If 1 = Interlocked.Increment(instanceCount) Then
Throw New ApplicationException("Throw only ONCE.")
End If
initBy = Thread.CurrentThread.ManagedThreadId
Console.WriteLine("LargeObject was created on thread id {0}.", initBy)
End Sub
この例を実行すると、LargeObject
のインスタンスを作成しようとする最初のスレッドが失敗し、例外がキャッチされます。 次のスレッドでインスタンスが正常に作成されると予想される場合がありますが、Lazy<T> オブジェクトによって例外がキャッシュされています。 このため、3 つのスレッドすべてが例外をスローします。
手記
わかりやすくするために、この例では Lazy<T>のグローバル インスタンスを使用し、すべてのメソッドが static
されます (Visual Basic ではShared
)。 これらは、遅延初期化を使用するための要件ではありません。
using System;
using System.Threading;
class Program
{
static Lazy<LargeObject> lazyLargeObject = null;
static LargeObject InitLargeObject()
{
return new LargeObject();
}
static void Main()
{
// The lazy initializer is created here. LargeObject is not created until the
// ThreadProc method executes.
lazyLargeObject = new Lazy<LargeObject>(InitLargeObject);
// The following lines show how to use other constructors to achieve exactly the
// same result as the previous line:
//lazyLargeObject = new Lazy<LargeObject>(InitLargeObject, true);
//lazyLargeObject = new Lazy<LargeObject>(InitLargeObject, LazyThreadSafetyMode.ExecutionAndPublication);
Console.WriteLine(
"\r\nLargeObject is not created until you access the Value property of the lazy" +
"\r\ninitializer. Press Enter to create LargeObject.");
Console.ReadLine();
// Create and start 3 threads, each of which tries to use LargeObject.
Thread[] threads = { new Thread(ThreadProc), new Thread(ThreadProc), new Thread(ThreadProc) };
foreach (Thread t in threads)
{
t.Start();
}
// Wait for all 3 threads to finish. (The order doesn't matter.)
foreach (Thread t in threads)
{
t.Join();
}
Console.WriteLine("\r\nPress Enter to end the program");
Console.ReadLine();
}
static void ThreadProc(object state)
{
try
{
LargeObject large = lazyLargeObject.Value;
// IMPORTANT: Lazy initialization is thread-safe, but it doesn't protect the
// object after creation. You must lock the object before accessing it,
// unless the type is thread safe. (LargeObject is not thread safe.)
lock(large)
{
large.Data[0] = Thread.CurrentThread.ManagedThreadId;
Console.WriteLine("Initialized by thread {0}; last used by thread {1}.",
large.InitializedBy, large.Data[0]);
}
}
catch (ApplicationException aex)
{
Console.WriteLine("Exception: {0}", aex.Message);
}
}
}
class LargeObject
{
int initBy = 0;
public int InitializedBy { get { return initBy; } }
static int instanceCount = 0;
public LargeObject()
{
if (1 == Interlocked.Increment(ref instanceCount))
{
throw new ApplicationException("Throw only ONCE.");
}
initBy = Thread.CurrentThread.ManagedThreadId;
Console.WriteLine("LargeObject was created on thread id {0}.", initBy);
}
public long[] Data = new long[100000000];
}
/* This example produces output similar to the following:
LargeObject is not created until you access the Value property of the lazy
initializer. Press Enter to create LargeObject.
Exception: Throw only ONCE.
Exception: Throw only ONCE.
Exception: Throw only ONCE.
Press Enter to end the program
*/
open System
open System.Threading
type LargeObject() =
static let mutable instanceCount = 0
let initBy = Thread.CurrentThread.ManagedThreadId
do
if 1 = Interlocked.Increment &instanceCount then
raise (ApplicationException "Throw only ONCE.")
printfn $"LargeObject was created on thread id {initBy}."
member _.InitializedBy = initBy
member val Data = Array.zeroCreate<int64> 100000000
let initLargeObject () =
LargeObject()
// The lazy initializer is created here. LargeObject is not created until the
// ThreadProc method executes.
let lazyLargeObject = Lazy<LargeObject> initLargeObject
// The following lines show how to use other constructors to achieve exactly the
// same result as the previous line:
// let lazyLargeObject = Lazy<LargeObject>(initLargeObject, true)
// let lazyLargeObject = Lazy<LargeObject>(initLargeObject, LazyThreadSafetyMode.ExecutionAndPublication)
let threadProc _ =
try
let large = lazyLargeObject.Value
// IMPORTANT: Lazy initialization is thread-safe, but it doesn't protect the
// object after creation. You must lock the object before accessing it,
// unless the type is thread safe. (LargeObject is not thread safe.)
lock large (fun () ->
large.Data[0] <- Thread.CurrentThread.ManagedThreadId
printfn $"Initialized by thread {large.InitializedBy} last used by thread {large.Data[0]}.")
with :? ApplicationException as aex ->
printfn $"Exception: {aex.Message}"
printfn """
LargeObject is not created until you access the Value property of the lazy
initializer. Press Enter to create LargeObject."""
stdin.ReadLine () |> ignore
// Create and start 3 threads, each of which tries to use LargeObject.
let threads =
[| Thread(ParameterizedThreadStart threadProc); Thread(ParameterizedThreadStart threadProc); Thread(ParameterizedThreadStart threadProc) |]
for t in threads do
t.Start()
// Wait for all 3 threads to finish. (The order doesn't matter.)
for t in threads do
t.Join()
printfn "\nPress Enter to end the program"
stdin.ReadLine() |> ignore
// This example produces output similar to the following:
// LargeObject is not created until you access the Value property of the lazy
// initializer. Press Enter to create LargeObject.
//
// Exception: Throw only ONCE.
// Exception: Throw only ONCE.
// Exception: Throw only ONCE.
//
// Press Enter to end the program
Imports System.Threading
Friend Class Program
Private Shared lazyLargeObject As Lazy(Of LargeObject) = Nothing
Private Shared Function InitLargeObject() As LargeObject
Return New LargeObject()
End Function
Shared Sub Main()
' The lazy initializer is created here. LargeObject is not created until the
' ThreadProc method executes.
lazyLargeObject = New Lazy(Of LargeObject)(AddressOf InitLargeObject)
' The following lines show how to use other constructors to achieve exactly the
' same result as the previous line:
'lazyLargeObject = New Lazy(Of LargeObject)(AddressOf InitLargeObject, True)
'lazyLargeObject = New Lazy(Of LargeObject)(AddressOf InitLargeObject, LazyThreadSafetyMode.ExecutionAndPublication)
Console.WriteLine(vbCrLf _
& "LargeObject is not created until you access the Value property of the lazy" _
& vbCrLf & "initializer. Press Enter to create LargeObject.")
Console.ReadLine()
' Create and start 3 threads, each of which tries to use LargeObject.
Dim threads() As Thread = { New Thread(AddressOf ThreadProc), _
New Thread(AddressOf ThreadProc), New Thread(AddressOf ThreadProc) }
For Each t As Thread In threads
t.Start()
Next t
' Wait for all 3 threads to finish. (The order doesn't matter.)
For Each t As Thread In threads
t.Join()
Next t
Console.WriteLine(vbCrLf & "Press Enter to end the program")
Console.ReadLine()
End Sub
Private Shared Sub ThreadProc(ByVal state As Object)
Try
Dim large As LargeObject = lazyLargeObject.Value
' IMPORTANT: Lazy initialization is thread-safe, but it doesn't protect the
' object after creation. You must lock the object before accessing it,
' unless the type is thread safe. (LargeObject is not thread safe.)
SyncLock large
large.Data(0) = Thread.CurrentThread.ManagedThreadId
Console.WriteLine("Initialized by thread {0}; last used by thread {1}.", _
large.InitializedBy, large.Data(0))
End SyncLock
Catch aex As ApplicationException
Console.WriteLine("Exception: {0}", aex.Message)
End Try
End Sub
End Class
Friend Class LargeObject
Private initBy As Integer = 0
Public ReadOnly Property InitializedBy() As Integer
Get
Return initBy
End Get
End Property
Private Shared instanceCount As Integer = 0
Public Sub New()
If 1 = Interlocked.Increment(instanceCount) Then
Throw New ApplicationException("Throw only ONCE.")
End If
initBy = Thread.CurrentThread.ManagedThreadId
Console.WriteLine("LargeObject was created on thread id {0}.", initBy)
End Sub
Public Data(99999999) As Long
End Class
' This example produces output similar to the following:
'
'LargeObject is not created until you access the Value property of the lazy
'initializer. Press Enter to create LargeObject.
'
'Exception: Throw only ONCE.
'Exception: Throw only ONCE.
'Exception: Throw only ONCE.
'
'Press Enter to end the program
'
注釈
このコンストラクターで作成されたインスタンスは、複数のスレッドから同時に使用できます。
このコンストラクターで初期化される Lazy<T> インスタンスのスレッド セーフ モードは LazyThreadSafetyMode.ExecutionAndPublication。 スレッド セーフ モードは、複数のスレッドが Lazy<T> インスタンスを初期化しようとしたときの動作を表します。
valueFactory
によってスローされる例外はキャッシュされます。 詳細については、Lazy<T> クラスまたは System.Threading.LazyThreadSafetyMode 列挙体を参照してください。
こちらもご覧ください
- 遅延初期化 の
適用対象
Lazy<T>(LazyThreadSafetyMode)
- ソース:
- Lazy.cs
- ソース:
- Lazy.cs
- ソース:
- Lazy.cs
T
のパラメーターなしのコンストラクターと指定したスレッド セーフ モードを使用する Lazy<T> クラスの新しいインスタンスを初期化します。
public:
Lazy(System::Threading::LazyThreadSafetyMode mode);
public Lazy (System.Threading.LazyThreadSafetyMode mode);
new Lazy<'T> : System.Threading.LazyThreadSafetyMode -> Lazy<'T>
Public Sub New (mode As LazyThreadSafetyMode)
パラメーター
- mode
- LazyThreadSafetyMode
スレッド セーフ モードを指定する列挙値の 1 つ。
例外
mode
に無効な値が含まれています。
例
次の例では、このコンストラクターを使用して遅延初期化子を作成し、複数のスレッドがオブジェクトを遅延して作成する競合を可能にします。 複数のスレッドがインスタンスの作成に成功する可能性がありますが、すべてのスレッドが最初に作成されたインスタンスを使用します。
手記
シングル スレッドのシナリオでこのコンストラクターを使用する方法を示す例 (mode
の LazyThreadSafetyMode.None を指定する) については、Lazy<T>(Boolean) コンストラクターを参照してください。 マルチスレッド シナリオで競合状態ではなくロックを提供するためにこのコンストラクターを使用する方法を示す例 (mode
の LazyThreadSafetyMode.ExecutionAndPublication を指定する) については、Lazy<T>() コンストラクターを参照してください。
この例では、複数のスレッドのいずれかによって遅延的に初期化される LargeObject
クラスを定義します。 コードの 3 つの主要なセクションは、初期化子の作成、実際の初期化、および LargeObject
クラスのコンストラクターとファイナライザーを示しています。 この例では、Main
メソッドの先頭に、LargeObject
の遅延初期化を実行する Lazy<T> オブジェクトを作成します。
lazyLargeObject = new Lazy<LargeObject>(LazyThreadSafetyMode.PublicationOnly);
let lazyLargeObject = Lazy<LargeObject> LazyThreadSafetyMode.PublicationOnly
lazyLargeObject = New Lazy(Of LargeObject)(LazyThreadSafetyMode.PublicationOnly)
この例では、ManualResetEvent オブジェクトでブロックする 3 つのスレッドを作成して開始します。この例では、スレッドをすべて一度に解放できます。 3 つのスレッドすべてで使用される ThreadProc
メソッドで、Value プロパティを呼び出すと、LargeObject
インスタンスが作成されます。
LargeObject large = lazyLargeObject.Value;
let large = lazyLargeObject.Value
Dim large As LargeObject = lazyLargeObject.Value
Lazy<T> インスタンスのコンストラクターは LazyThreadSafetyMode.PublicationOnly指定されているため、3 つのスレッドはすべて LargeObject
インスタンスを作成できます。 この例では、コンストラクターと LargeObject
クラスのファイナライザーにコンソール メッセージを表示することで、これを示します。
public LargeObject()
{
initBy = Thread.CurrentThread.ManagedThreadId;
Console.WriteLine("Constructor: Instance initializing on thread {0}", initBy);
}
~LargeObject()
{
Console.WriteLine("Finalizer: Instance was initialized on {0}", initBy);
}
type LargeObject() =
let initBy = Thread.CurrentThread.ManagedThreadId
do
printfn $"Constructor: Instance initializing on thread {initBy}"
override _.Finalize() =
printfn $"Finalizer: Instance was initialized on {initBy}"
Public Sub New()
initBy = Thread.CurrentThread.ManagedThreadId
Console.WriteLine("Constructor: Instance initializing on thread {0}", initBy)
End Sub
Protected Overrides Sub Finalize()
Console.WriteLine("Finalizer: Instance was initialized on {0}", initBy)
End Sub
ただし、Lazy<T> オブジェクトを使用すると、すべてのスレッドで 1 つのインスタンスのみが使用されます。 この例の出力は、3 つのスレッドすべてが同じインスタンスを使用していることを示しています。また、他の 2 つのインスタンスをガベージ コレクションで再利用できることを示しています。
手記
わかりやすくするために、この例では Lazy<T>のグローバル インスタンスを使用し、すべてのメソッドが static
されます (Visual Basic ではShared
)。 これらは、遅延初期化を使用するための要件ではありません。
using System;
using System.Threading;
class Program
{
static Lazy<LargeObject> lazyLargeObject = null;
static void Main()
{
// The lazy initializer is created here. LargeObject is not created until the
// ThreadProc method executes.
lazyLargeObject = new Lazy<LargeObject>(LazyThreadSafetyMode.PublicationOnly);
// Create and start 3 threads, passing the same blocking event to all of them.
ManualResetEvent startingGate = new ManualResetEvent(false);
Thread[] threads = { new Thread(ThreadProc), new Thread(ThreadProc), new Thread(ThreadProc) };
foreach (Thread t in threads)
{
t.Start(startingGate);
}
// Give all 3 threads time to start and wait, then release them all at once.
Thread.Sleep(50);
startingGate.Set();
// Wait for all 3 threads to finish. (The order doesn't matter.)
foreach (Thread t in threads)
{
t.Join();
}
Console.WriteLine(
"\r\nThreads are complete. Running GC.Collect() to reclaim the extra instances.");
GC.Collect();
// Allow time for garbage collection, which happens asynchronously.
Thread.Sleep(100);
Console.WriteLine(
"\r\nNote that all three threads used the instance that was not collected.");
Console.WriteLine("Press Enter to end the program");
Console.ReadLine();
}
static void ThreadProc(object state)
{
// Wait for the signal.
ManualResetEvent waitForStart = (ManualResetEvent) state;
waitForStart.WaitOne();
LargeObject large = lazyLargeObject.Value;
// The following line introduces an artificial delay, to exaggerate the race
// condition.
Thread.Sleep(5);
// IMPORTANT: Lazy initialization is thread-safe, but it doesn't protect the
// object after creation. You must lock the object before accessing it,
// unless the type is thread safe. (LargeObject is not thread safe.)
lock(large)
{
large.Data[0] = Thread.CurrentThread.ManagedThreadId;
Console.WriteLine("LargeObject was initialized by thread {0}; last used by thread {1}.",
large.InitializedBy, large.Data[0]);
}
}
}
class LargeObject
{
int initBy = -1;
public int InitializedBy { get { return initBy; } }
public LargeObject()
{
initBy = Thread.CurrentThread.ManagedThreadId;
Console.WriteLine("Constructor: Instance initializing on thread {0}", initBy);
}
~LargeObject()
{
Console.WriteLine("Finalizer: Instance was initialized on {0}", initBy);
}
public long[] Data = new long[100000000];
}
/* This example produces output similar to the following:
Constructor: Instance initializing on thread 4
Constructor: Instance initializing on thread 3
Constructor: Instance initializing on thread 5
LargeObject was initialized by thread 4; last used by thread 4.
LargeObject was initialized by thread 4; last used by thread 5.
LargeObject was initialized by thread 4; last used by thread 3.
Threads are complete. Running GC.Collect() to reclaim the extra instances.
Finalizer: Instance was initialized on 3
Finalizer: Instance was initialized on 5
Note that all three threads used the instance that was not collected.
Press Enter to end the program
Instance finalizing; initialized on 4
*/
open System
open System.Threading
type LargeObject() =
let initBy = Thread.CurrentThread.ManagedThreadId
do
printfn $"Constructor: Instance initializing on thread {initBy}"
override _.Finalize() =
printfn $"Finalizer: Instance was initialized on {initBy}"
member _.InitializedBy = initBy
member val Data = Array.zeroCreate<int64> 100000000
// The lazy initializer is created here. LargeObject is not created until the
// ThreadProc method executes.
let lazyLargeObject = Lazy<LargeObject> LazyThreadSafetyMode.PublicationOnly
let threadProc (state: obj) =
// Wait for the signal.
let waitForStart = state :?> ManualResetEvent
waitForStart.WaitOne() |> ignore
let large = lazyLargeObject.Value
// The following line introduces an artificial delay, to exaggerate the race
// condition.
Thread.Sleep 5
// IMPORTANT: Lazy initialization is thread-safe, but it doesn't protect the
// object after creation. You must lock the object before accessing it,
// unless the type is thread safe. (LargeObject is not thread safe.)
lock large (fun () ->
large.Data[0] <- Thread.CurrentThread.ManagedThreadId
printfn $"LargeObject was initialized by thread {large.InitializedBy} last used by thread {large.Data[0]}.")
// Create and start 3 threads, passing the same blocking event to all of them.
let startingGate = new ManualResetEvent false
let threads =
[| Thread(ParameterizedThreadStart threadProc); Thread(ParameterizedThreadStart threadProc); Thread(ParameterizedThreadStart threadProc) |]
for t in threads do
t.Start startingGate
// Give all 3 threads time to start and wait, then release them all at once.
Thread.Sleep 50
startingGate.Set() |> ignore
// Wait for all 3 threads to finish. (The order doesn't matter.)
for t in threads do
t.Join()
printfn "\nThreads are complete. Running GC.Collect() to reclaim the extra instances."
GC.Collect()
// Allow time for garbage collection, which happens asynchronously.
Thread.Sleep 100
printfn "\nNote that all three threads used the instance that was not collected."
printfn "Press Enter to end the program"
stdin.ReadLine() |> ignore
// This example produces output similar to the following:
// Constructor: Instance initializing on thread 4
// Constructor: Instance initializing on thread 3
// Constructor: Instance initializing on thread 5
// LargeObject was initialized by thread 4 last used by thread 4.
// LargeObject was initialized by thread 4 last used by thread 5.
// LargeObject was initialized by thread 4 last used by thread 3.
//
// Threads are complete. Running GC.Collect() to reclaim the extra instances.
// Finalizer: Instance was initialized on 3
// Finalizer: Instance was initialized on 5
//
// Note that all three threads used the instance that was not collected.
// Press Enter to end the program
//
// Instance finalizing initialized on 4
Imports System.Threading
Friend Class Program
Private Shared lazyLargeObject As Lazy(Of LargeObject) = Nothing
Shared Sub Main()
' The lazy initializer is created here. LargeObject is not created until the
' ThreadProc method executes.
lazyLargeObject = New Lazy(Of LargeObject)(LazyThreadSafetyMode.PublicationOnly)
' Create and start 3 threads, passing the same blocking event to all of them.
Dim startingGate As New ManualResetEvent(False)
Dim threads() As Thread = { _
New Thread(AddressOf ThreadProc), _
New Thread(AddressOf ThreadProc), _
New Thread(AddressOf ThreadProc) _
}
For Each t As Thread In threads
t.Start(startingGate)
Next t
' Give all 3 threads time to start and wait, then release them all at once.
Thread.Sleep(50)
startingGate.Set()
' Wait for all 3 threads to finish. (The order doesn't matter.)
For Each t As Thread In threads
t.Join()
Next t
Console.WriteLine(vbCrLf & _
"Threads are complete. Running GC.Collect() to reclaim the extra instances.")
GC.Collect()
' Allow time for garbage collection, which happens asynchronously.
Thread.Sleep(100)
Console.WriteLine(vbCrLf & _
"Note that all three threads used the instance that was not collected.")
Console.WriteLine("Press Enter to end the program")
Console.ReadLine()
End Sub
Private Shared Sub ThreadProc(ByVal state As Object)
' Wait for the signal.
Dim waitForStart As ManualResetEvent = CType(state, ManualResetEvent)
waitForStart.WaitOne()
Dim large As LargeObject = lazyLargeObject.Value
' The following line introduces an artificial delay to exaggerate the race condition.
Thread.Sleep(5)
' IMPORTANT: Lazy initialization is thread-safe, but it doesn't protect the
' object after creation. You must lock the object before accessing it,
' unless the type is thread safe. (LargeObject is not thread safe.)
SyncLock large
large.Data(0) = Thread.CurrentThread.ManagedThreadId
Console.WriteLine( _
"LargeObject was initialized by thread {0}; last used by thread {1}.", _
large.InitializedBy, large.Data(0))
End SyncLock
End Sub
End Class
Friend Class LargeObject
Private initBy As Integer = -1
Public ReadOnly Property InitializedBy() As Integer
Get
Return initBy
End Get
End Property
Public Sub New()
initBy = Thread.CurrentThread.ManagedThreadId
Console.WriteLine("Constructor: Instance initializing on thread {0}", initBy)
End Sub
Protected Overrides Sub Finalize()
Console.WriteLine("Finalizer: Instance was initialized on {0}", initBy)
End Sub
Public Data(100000000) As Long
End Class
' This example produces output similar to the following:
'
'Constructor: Instance initializing on thread 3
'Constructor: Instance initializing on thread 5
'Constructor: Instance initializing on thread 4
'LargeObject was initialized by thread 3; last used by thread 4.
'LargeObject was initialized by thread 3; last used by thread 3.
'LargeObject was initialized by thread 3; last used by thread 5.
'
'Threads are complete. Running GC.Collect() to reclaim the extra instances.
'Finalizer: Instance was initialized on 5
'Finalizer: Instance was initialized on 4
'
'Note that all three threads used the instance that was not collected.
'Press Enter to end the program
'
'Finalizer: Instance was initialized on 3
'
注釈
Lazy<T> インスタンスのスレッド セーフ モードでは、複数のスレッドが Lazy<T> インスタンスを初期化しようとしたときの動作が記述されます。
このコンストラクターで作成された Lazy<T> インスタンスは、例外をキャッシュしません。 詳細については、Lazy<T> クラスまたは System.Threading.LazyThreadSafetyMode 列挙体を参照してください。
こちらもご覧ください
- LazyThreadSafetyMode
- 遅延初期化 の
適用対象
Lazy<T>(T)
Lazy<T>(Func<T>, Boolean)
- ソース:
- Lazy.cs
- ソース:
- Lazy.cs
- ソース:
- Lazy.cs
Lazy<T> クラスの新しいインスタンスを初期化します。 遅延初期化が発生すると、指定された初期化関数と初期化モードが使用されます。
public:
Lazy(Func<T> ^ valueFactory, bool isThreadSafe);
public Lazy (Func<T> valueFactory, bool isThreadSafe);
new Lazy<'T> : Func<'T> * bool -> Lazy<'T>
Public Sub New (valueFactory As Func(Of T), isThreadSafe As Boolean)
パラメーター
- valueFactory
- Func<T>
必要に応じて遅延初期化値を生成するために呼び出されるデリゲート。
- isThreadSafe
- Boolean
このインスタンスを複数のスレッドで同時に使用できるようにする true
。false
、このインスタンスを一度に 1 つのスレッドでのみ使用できるようにします。
例外
valueFactory
は null
です。
例
次の例では、このコンストラクターを使用して、単一のスレッドを使用するシナリオで、例外キャッシュを使用して遅延初期化を提供する方法を示します。 また、Lazy<T> コンストラクター (mode
の LazyThreadSafetyMode.None を指定する) の使用方法も示します。 そのコンストラクターに切り替えるには、コメント アウトするコンストラクターを変更するだけです。
手記
マルチスレッド シナリオでこのコンストラクターを使用する方法を示すコード (isThreadSafe
の true
を指定) については、Lazy<T>(Func<T>) コンストラクターの例を参照してください。
この例では、複数のスレッドの 1 つによって遅延的に初期化される LargeObject
クラスを定義します。 コードの 3 つの主要なセクションは、初期化子の作成、実際の初期化、および例外キャッシュを示す LargeObject
クラスのコンストラクターを示しています。 この例では、Main
メソッドの先頭に、LargeObject
のスレッド セーフな遅延初期化子を作成します。
lazyLargeObject = new Lazy<LargeObject>(InitLargeObject, false);
// The following lines show how to use other constructors to achieve exactly the
// same result as the previous line:
//lazyLargeObject = new Lazy<LargeObject>(InitLargeObject, LazyThreadSafetyMode.None);
let lazyLargeObject = Lazy<LargeObject>(initLargeObject, false)
// The following lines show how to use other constructors to achieve exactly the
// same result as the previous line:
// let lazyLargeObject = Lazy<LargeObject>(initLargeObject, LazyThreadSafetyMode.None)
lazyLargeObject = New Lazy(Of LargeObject)(AddressOf InitLargeObject, False)
' The following lines show how to use other constructors to achieve exactly the
' same result as the previous line:
'lazyLargeObject = New Lazy(Of LargeObject)(AddressOf InitLargeObject, LazyThreadSafetyMode.None)
コンストラクターの呼び出しでは、isThreadSafe
パラメーターが false
されるため、Lazy<T> はスレッド セーフではありません。 スレッド セーフではないため、この例では、同じスレッドで Value プロパティを 3 回呼び出します。
for (int i = 0; i < 3; i++)
{
try
{
LargeObject large = lazyLargeObject.Value;
large.Data[11] = 89;
}
catch (ApplicationException aex)
{
Console.WriteLine("Exception: {0}", aex.Message);
}
}
for _ = 0 to 2 do
try
let large = lazyLargeObject.Value
large.Data[11] <- 89
with :? ApplicationException as aex ->
printfn $"Exception: {aex.Message}"
For i As Integer = 0 To 2
Try
Dim large As LargeObject = lazyLargeObject.Value
large.Data(11) = 89
Catch aex As ApplicationException
Console.WriteLine("Exception: {0}", aex.Message)
End Try
Next i
LargeObject
クラスのコンストラクターでは、コードの 3 番目のキー セクションでは、LargeObject
インスタンスが初めて作成されるときに例外がスローされますが、その後、インスタンスの作成が可能になります。
static bool pleaseThrow = true;
public LargeObject()
{
if (pleaseThrow)
{
pleaseThrow = false;
throw new ApplicationException("Throw only ONCE.");
}
Console.WriteLine("LargeObject was created on thread id {0}.",
Thread.CurrentThread.ManagedThreadId);
}
type LargeObject() =
static let mutable pleaseThrow = true
do
if pleaseThrow then
pleaseThrow <- false
raise (ApplicationException "Throw only ONCE.")
printfn $"LargeObject was created on thread id {Thread.CurrentThread.ManagedThreadId}."
Private Shared pleaseThrow As Boolean = True
Public Sub New()
If pleaseThrow Then
pleaseThrow = False
Throw New ApplicationException("Throw only ONCE.")
End If
Console.WriteLine("LargeObject was created on thread id {0}.", _
Thread.CurrentThread.ManagedThreadId)
End Sub
この例を実行すると、LargeObject
のインスタンスを最初に作成しようとすると失敗し、例外がキャッチされます。 次の試行は成功する可能性がありますが、Lazy<T> オブジェクトによって例外がキャッシュされています。 このため、3 回すべての試行で例外がスローされます。
手記
わかりやすくするために、この例では Lazy<T>のグローバル インスタンスを使用し、すべてのメソッドが static
されます (Visual Basic ではShared
)。 これらは、遅延初期化を使用するための要件ではありません。
using System;
using System.Threading;
class Program
{
static Lazy<LargeObject> lazyLargeObject = null;
static LargeObject InitLargeObject()
{
return new LargeObject();
}
static void Main()
{
// The lazy initializer is created here. LargeObject is not created until the
// ThreadProc method executes.
lazyLargeObject = new Lazy<LargeObject>(InitLargeObject, false);
// The following lines show how to use other constructors to achieve exactly the
// same result as the previous line:
//lazyLargeObject = new Lazy<LargeObject>(InitLargeObject, LazyThreadSafetyMode.None);
Console.WriteLine(
"\r\nLargeObject is not created until you access the Value property of the lazy" +
"\r\ninitializer. Press Enter to create LargeObject (three tries).");
Console.ReadLine();
for (int i = 0; i < 3; i++)
{
try
{
LargeObject large = lazyLargeObject.Value;
large.Data[11] = 89;
}
catch (ApplicationException aex)
{
Console.WriteLine("Exception: {0}", aex.Message);
}
}
Console.WriteLine("\r\nPress Enter to end the program");
Console.ReadLine();
}
}
class LargeObject
{
static bool pleaseThrow = true;
public LargeObject()
{
if (pleaseThrow)
{
pleaseThrow = false;
throw new ApplicationException("Throw only ONCE.");
}
Console.WriteLine("LargeObject was created on thread id {0}.",
Thread.CurrentThread.ManagedThreadId);
}
public long[] Data = new long[100000000];
}
/* This example produces output similar to the following:
LargeObject is not created until you access the Value property of the lazy
initializer. Press Enter to create LargeObject (three tries).
Exception: Throw only ONCE.
Exception: Throw only ONCE.
Exception: Throw only ONCE.
Press Enter to end the program
*/
open System
open System.Threading
type LargeObject() =
static let mutable pleaseThrow = true
do
if pleaseThrow then
pleaseThrow <- false
raise (ApplicationException "Throw only ONCE.")
printfn $"LargeObject was created on thread id {Thread.CurrentThread.ManagedThreadId}."
member val Data = Array.zeroCreate<int64> 100000000
let initLargeObject () =
LargeObject()
// The lazy initializer is created here. LargeObject is not created until the
// ThreadProc method executes.
let lazyLargeObject = Lazy<LargeObject>(initLargeObject, false)
// The following lines show how to use other constructors to achieve exactly the
// same result as the previous line:
// let lazyLargeObject = Lazy<LargeObject>(initLargeObject, LazyThreadSafetyMode.None)
printfn """
LargeObject is not created until you access the Value property of the lazy
initializer. Press Enter to create LargeObject (three tries)."""
stdin.ReadLine() |> ignore
for _ = 0 to 2 do
try
let large = lazyLargeObject.Value
large.Data[11] <- 89
with :? ApplicationException as aex ->
printfn $"Exception: {aex.Message}"
printfn "\nPress Enter to end the program"
stdin.ReadLine() |> ignore
// This example produces output similar to the following:
// LargeObject is not created until you access the Value property of the lazy
// initializer. Press Enter to create LargeObject (three tries).
//
// Exception: Throw only ONCE.
// Exception: Throw only ONCE.
// Exception: Throw only ONCE.
//
// Press Enter to end the program
Imports System.Threading
Friend Class Program
Private Shared lazyLargeObject As Lazy(Of LargeObject) = Nothing
Private Shared Function InitLargeObject() As LargeObject
Return New LargeObject()
End Function
Shared Sub Main()
' The lazy initializer is created here. LargeObject is not created until the
' ThreadProc method executes.
lazyLargeObject = New Lazy(Of LargeObject)(AddressOf InitLargeObject, False)
' The following lines show how to use other constructors to achieve exactly the
' same result as the previous line:
'lazyLargeObject = New Lazy(Of LargeObject)(AddressOf InitLargeObject, LazyThreadSafetyMode.None)
Console.WriteLine(vbCrLf _
& "LargeObject is not created until you access the Value property of the lazy" _
& vbCrLf & "initializer. Press Enter to create LargeObject (three tries).")
Console.ReadLine()
For i As Integer = 0 To 2
Try
Dim large As LargeObject = lazyLargeObject.Value
large.Data(11) = 89
Catch aex As ApplicationException
Console.WriteLine("Exception: {0}", aex.Message)
End Try
Next i
Console.WriteLine(vbCrLf & "Press Enter to end the program")
Console.ReadLine()
End Sub
End Class
Friend Class LargeObject
Private Shared pleaseThrow As Boolean = True
Public Sub New()
If pleaseThrow Then
pleaseThrow = False
Throw New ApplicationException("Throw only ONCE.")
End If
Console.WriteLine("LargeObject was created on thread id {0}.", _
Thread.CurrentThread.ManagedThreadId)
End Sub
Public Data(100000000) As Long
End Class
' This example produces output similar to the following:
'
'LargeObject is not created until you access the Value property of the lazy
'initializer. Press Enter to create LargeObject (three tries).
'
'Exception: Throw only ONCE.
'Exception: Throw only ONCE.
'Exception: Throw only ONCE.
'
'Press Enter to end the program
'
注釈
このコンストラクターで初期化される Lazy<T> インスタンスのスレッド セーフ モードは、isThreadSafe
が true
されている場合に LazyThreadSafetyMode.ExecutionAndPublication されます。それ以外の場合、モードは LazyThreadSafetyMode.None。 スレッド セーフ モードは、複数のスレッドが Lazy<T> インスタンスを初期化しようとしたときの動作を表します。
LazyThreadSafetyMode.PublicationOnly モードを指定するには、Lazy<T>(Func<T>, LazyThreadSafetyMode) または Lazy<T>(LazyThreadSafetyMode) コンストラクターを使用します。
valueFactory
によってスローされる例外はキャッシュされます。 詳細については、Lazy<T> クラスまたは System.Threading.LazyThreadSafetyMode 列挙体を参照してください。
こちらもご覧ください
- 遅延初期化 の
適用対象
Lazy<T>(Func<T>, LazyThreadSafetyMode)
- ソース:
- Lazy.cs
- ソース:
- Lazy.cs
- ソース:
- Lazy.cs
指定した初期化関数とスレッド セーフ モードを使用する Lazy<T> クラスの新しいインスタンスを初期化します。
public:
Lazy(Func<T> ^ valueFactory, System::Threading::LazyThreadSafetyMode mode);
public Lazy (Func<T> valueFactory, System.Threading.LazyThreadSafetyMode mode);
new Lazy<'T> : Func<'T> * System.Threading.LazyThreadSafetyMode -> Lazy<'T>
Public Sub New (valueFactory As Func(Of T), mode As LazyThreadSafetyMode)
パラメーター
- valueFactory
- Func<T>
必要に応じて遅延初期化値を生成するために呼び出されるデリゲート。
- mode
- LazyThreadSafetyMode
スレッド セーフ モードを指定する列挙値の 1 つ。
例外
mode
に無効な値が含まれています。
valueFactory
は null
です。
例
次の例では、このコンストラクターを使用して遅延初期化子を作成し、複数のスレッドがオブジェクトを遅延して作成する競合を可能にします。 複数のスレッドがインスタンスの作成に成功する可能性がありますが、すべてのスレッドが最初に作成されたインスタンスを使用します。 さらに、この例では、遅延作成型のパラメーターなしのコンストラクターではなく関数によって初期化が実行される場合でも、LazyThreadSafetyMode.PublicationOnlyを指定しても例外がキャッシュされないという例を示しています。
手記
シングル スレッドのシナリオでこのコンストラクターを使用する方法を示す例 (mode
の LazyThreadSafetyMode.None を指定する) については、Lazy<T>(Boolean) コンストラクターを参照してください。 マルチスレッド シナリオで競合状態ではなくロックを提供するためにこのコンストラクターを使用する方法を示す例 (mode
の LazyThreadSafetyMode.ExecutionAndPublication を指定する) については、Lazy<T>() コンストラクターを参照してください。
この例では、複数のスレッドのいずれかによって遅延的に初期化される LargeObject
クラスを定義します。 コードの 4 つの主要なセクションは、初期化子の作成、実際の初期化、初期化関数、および LargeObject
クラスのコンストラクターとファイナライザーを示しています。 この例では、Main
メソッドの先頭に、LargeObject
の遅延初期化を実行する Lazy<T> オブジェクトを作成します。
lazyLargeObject = new Lazy<LargeObject>(InitLargeObject,
LazyThreadSafetyMode.PublicationOnly);
let lazyLargeObject = Lazy<LargeObject>(initLargeObject, LazyThreadSafetyMode.PublicationOnly)
lazyLargeObject = New Lazy(Of LargeObject)(AddressOf InitLargeObject, _
LazyThreadSafetyMode.PublicationOnly)
遅延初期化子は、関数を使用して初期化を実行します。 この場合、LargeObject
クラスにパラメーターなしのコンストラクターがないため、関数が必要です。
この例では、ManualResetEvent オブジェクトでブロックする 3 つのスレッドを作成して開始します。この例では、スレッドをすべて一度に解放できます。 3 つのスレッドすべてで使用される ThreadProc
メソッドで、Value プロパティを呼び出すと、LargeObject
インスタンスが作成されます。
LargeObject large = null;
try
{
large = lazyLargeObject.Value;
// The following line introduces an artificial delay to exaggerate the race condition.
Thread.Sleep(5);
// IMPORTANT: Lazy initialization is thread-safe, but it doesn't protect the
// object after creation. You must lock the object before accessing it,
// unless the type is thread safe. (LargeObject is not thread safe.)
lock(large)
{
large.Data[0] = Thread.CurrentThread.ManagedThreadId;
Console.WriteLine("LargeObject was initialized by thread {0}; last used by thread {1}.",
large.InitializedBy, large.Data[0]);
}
}
catch (ApplicationException ex)
{
Console.WriteLine("ApplicationException: {0}", ex.Message);
}
try
let large = lazyLargeObject.Value
// The following line introduces an artificial delay to exaggerate the race condition.
Thread.Sleep 5
// IMPORTANT: Lazy initialization is thread-safe, but it doesn't protect the
// object after creation. You must lock the object before accessing it,
// unless the type is thread safe. (LargeObject is not thread safe.)
lock large (fun () ->
large.Data[0] <- Thread.CurrentThread.ManagedThreadId
printfn $"LargeObject was initialized by thread {large.InitializedBy} last used by thread {large.Data[0]}.")
with :? ApplicationException as ex ->
printfn $"ApplicationException: {ex.Message}"
Dim large As LargeObject = Nothing
Try
large = lazyLargeObject.Value
' The following line introduces an artificial delay to exaggerate the race condition.
Thread.Sleep(5)
' IMPORTANT: Lazy initialization is thread-safe, but it doesn't protect the
' object after creation. You must lock the object before accessing it,
' unless the type is thread safe. (LargeObject is not thread safe.)
SyncLock large
large.Data(0) = Thread.CurrentThread.ManagedThreadId
Console.WriteLine( _
"LargeObject was initialized by thread {0}; last used by thread {1}.", _
large.InitializedBy, large.Data(0))
End SyncLock
Catch ex As ApplicationException
Console.WriteLine("ApplicationException: {0}", ex.Message)
End Try
コードの 3 番目のキー セクションでは、遅延初期化関数が呼び出され、LargeObject
インスタンスが作成されます。 この関数は、初めて呼び出されると例外をスローします。
static int instanceCount = 0;
static LargeObject InitLargeObject()
{
if (1 == Interlocked.Increment(ref instanceCount))
{
throw new ApplicationException(
String.Format("Lazy initialization function failed on thread {0}.",
Thread.CurrentThread.ManagedThreadId));
}
return new LargeObject(Thread.CurrentThread.ManagedThreadId);
}
let mutable instanceCount = 0
let initLargeObject () =
if 1 = Interlocked.Increment &instanceCount then
raise (ApplicationException $"Lazy initialization function failed on thread {Thread.CurrentThread.ManagedThreadId}.")
LargeObject Thread.CurrentThread.ManagedThreadId
Private Shared instanceCount As Integer = 0
Private Shared Function InitLargeObject() As LargeObject
If 1 = Interlocked.Increment(instanceCount) Then
Throw New ApplicationException( _
"Lazy initialization function failed on thread " & _
Thread.CurrentThread.ManagedThreadId & ".")
End If
Return New LargeObject(Thread.CurrentThread.ManagedThreadId)
End Function
その他の LazyThreadSafetyMode 設定では、初期化関数のハンドルされない例外がキャッシュされます。 ただし、LazyThreadSafetyMode.PublicationOnly は例外キャッシュを抑制します。 この例の出力は、オブジェクトを初期化する後続の試行が成功することを示しています。
手記
例外メッセージは通常、他のスレッドがオブジェクトを正常に初期化したことを示すメッセージの後に表示されます。 これは、例外をスローしてキャッチすることによって発生する遅延が原因です。
Lazy<T> インスタンスのコンストラクターは LazyThreadSafetyMode.PublicationOnly指定されているため、3 つのスレッドはすべて LargeObject
インスタンスを作成できます。 この例では、コンストラクターと LargeObject
クラスのファイナライザーにコンソール メッセージを表示することで、これを示します。
public LargeObject(int initializedBy)
{
initBy = initializedBy;
Console.WriteLine("Constructor: Instance initializing on thread {0}", initBy);
}
~LargeObject()
{
Console.WriteLine("Finalizer: Instance was initialized on {0}", initBy);
}
type LargeObject(initBy) =
do
printfn $"Constructor: Instance initializing on thread {initBy}"
override _.Finalize() =
printfn $"Finalizer: Instance was initialized on {initBy}"
Public Sub New(ByVal initializedBy As Integer)
initBy = initializedBy
Console.WriteLine("Constructor: Instance initializing on thread {0}", initBy)
End Sub
Protected Overrides Sub Finalize()
Console.WriteLine("Finalizer: Instance was initialized on {0}", initBy)
End Sub
Lazy<T> オブジェクトは、すべてのスレッドで使用されるインスタンスが 1 つだけであることを保証します (初期化関数が例外をスローするスレッドを除く)。 この例からの出力は、これを示しています。
手記
わかりやすくするために、この例では Lazy<T>のグローバル インスタンスを使用し、すべてのメソッドが static
されます (Visual Basic ではShared
)。 これらは、遅延初期化を使用するための要件ではありません。
using System;
using System.Threading;
class Program
{
static Lazy<LargeObject> lazyLargeObject = null;
// Factory function for lazy initialization.
static int instanceCount = 0;
static LargeObject InitLargeObject()
{
if (1 == Interlocked.Increment(ref instanceCount))
{
throw new ApplicationException(
String.Format("Lazy initialization function failed on thread {0}.",
Thread.CurrentThread.ManagedThreadId));
}
return new LargeObject(Thread.CurrentThread.ManagedThreadId);
}
static void Main()
{
// The lazy initializer is created here. LargeObject is not created until the
// ThreadProc method executes.
lazyLargeObject = new Lazy<LargeObject>(InitLargeObject,
LazyThreadSafetyMode.PublicationOnly);
// Create and start 3 threads, passing the same blocking event to all of them.
ManualResetEvent startingGate = new ManualResetEvent(false);
Thread[] threads = { new Thread(ThreadProc), new Thread(ThreadProc), new Thread(ThreadProc) };
foreach (Thread t in threads)
{
t.Start(startingGate);
}
// Give all 3 threads time to start and wait, then release them all at once.
Thread.Sleep(50);
startingGate.Set();
// Wait for all 3 threads to finish. (The order doesn't matter.)
foreach (Thread t in threads)
{
t.Join();
}
Console.WriteLine(
"\r\nThreads are complete. Running GC.Collect() to reclaim extra instances.");
GC.Collect();
// Allow time for garbage collection, which happens asynchronously.
Thread.Sleep(100);
Console.WriteLine("\r\nNote that only one instance of LargeObject was used.");
Console.WriteLine("Press Enter to end the program");
Console.ReadLine();
}
static void ThreadProc(object state)
{
// Wait for the signal.
ManualResetEvent waitForStart = (ManualResetEvent) state;
waitForStart.WaitOne();
LargeObject large = null;
try
{
large = lazyLargeObject.Value;
// The following line introduces an artificial delay to exaggerate the race condition.
Thread.Sleep(5);
// IMPORTANT: Lazy initialization is thread-safe, but it doesn't protect the
// object after creation. You must lock the object before accessing it,
// unless the type is thread safe. (LargeObject is not thread safe.)
lock(large)
{
large.Data[0] = Thread.CurrentThread.ManagedThreadId;
Console.WriteLine("LargeObject was initialized by thread {0}; last used by thread {1}.",
large.InitializedBy, large.Data[0]);
}
}
catch (ApplicationException ex)
{
Console.WriteLine("ApplicationException: {0}", ex.Message);
}
}
}
class LargeObject
{
int initBy = -1;
public int InitializedBy { get { return initBy; } }
public LargeObject(int initializedBy)
{
initBy = initializedBy;
Console.WriteLine("Constructor: Instance initializing on thread {0}", initBy);
}
~LargeObject()
{
Console.WriteLine("Finalizer: Instance was initialized on {0}", initBy);
}
public long[] Data = new long[100000000];
}
/* This example produces output similar to the following:
Constructor: Instance initializing on thread 5
Constructor: Instance initializing on thread 4
ApplicationException: Lazy initialization function failed on thread 3.
LargeObject was initialized by thread 5; last used by thread 5.
LargeObject was initialized by thread 5; last used by thread 4.
Threads are complete. Running GC.Collect() to reclaim extra instances.
Finalizer: Instance was initialized on 4
Note that only one instance of LargeObject was used.
Press Enter to end the program
Finalizer: Instance was initialized on 5
*/
open System
open System.Threading
type LargeObject(initBy) =
do
printfn $"Constructor: Instance initializing on thread {initBy}"
override _.Finalize() =
printfn $"Finalizer: Instance was initialized on {initBy}"
member _.InitializedBy = initBy
member val Data = Array.zeroCreate<int64> 100000000 with get
// Factory function for lazy initialization.
let mutable instanceCount = 0
let initLargeObject () =
if 1 = Interlocked.Increment &instanceCount then
raise (ApplicationException $"Lazy initialization function failed on thread {Thread.CurrentThread.ManagedThreadId}.")
LargeObject Thread.CurrentThread.ManagedThreadId
// The lazy initializer is created here. LargeObject is not created until the
// ThreadProc method executes.
let lazyLargeObject = Lazy<LargeObject>(initLargeObject, LazyThreadSafetyMode.PublicationOnly)
let threadProc (state: obj) =
// Wait for the signal.
let waitForStart = state :?> ManualResetEvent
waitForStart.WaitOne() |> ignore
try
let large = lazyLargeObject.Value
// The following line introduces an artificial delay to exaggerate the race condition.
Thread.Sleep 5
// IMPORTANT: Lazy initialization is thread-safe, but it doesn't protect the
// object after creation. You must lock the object before accessing it,
// unless the type is thread safe. (LargeObject is not thread safe.)
lock large (fun () ->
large.Data[0] <- Thread.CurrentThread.ManagedThreadId
printfn $"LargeObject was initialized by thread {large.InitializedBy} last used by thread {large.Data[0]}.")
with :? ApplicationException as ex ->
printfn $"ApplicationException: {ex.Message}"
// Create and start 3 threads, passing the same blocking event to all of them.
let startingGate = new ManualResetEvent false
let threads =
[| Thread(ParameterizedThreadStart threadProc); Thread(ParameterizedThreadStart threadProc); Thread(ParameterizedThreadStart threadProc) |]
for t in threads do
t.Start startingGate
// Give all 3 threads time to start and wait, then release them all at once.
Thread.Sleep 50
startingGate.Set() |> ignore
// Wait for all 3 threads to finish. (The order doesn't matter.)
for t in threads do
t.Join()
printfn "\nThreads are complete. Running GC.Collect() to reclaim extra instances."
GC.Collect()
// Allow time for garbage collection, which happens asynchronously.
Thread.Sleep 100
printfn "\nNote that only one instance of LargeObject was used."
printfn "Press Enter to end the program"
stdin.ReadLine() |> ignore
// This example produces output similar to the following:
// Constructor: Instance initializing on thread 5
// Constructor: Instance initializing on thread 4
// ApplicationException: Lazy initialization function failed on thread 3.
// LargeObject was initialized by thread 5 last used by thread 5.
// LargeObject was initialized by thread 5 last used by thread 4.
//
// Threads are complete. Running GC.Collect() to reclaim extra instances.
// Finalizer: Instance was initialized on 4
//
// Note that only one instance of LargeObject was used.
// Press Enter to end the program
//
// Finalizer: Instance was initialized on 5
Imports System.Threading
Friend Class Program
Private Shared lazyLargeObject As Lazy(Of LargeObject) = Nothing
' Factory function for lazy initialization.
Private Shared instanceCount As Integer = 0
Private Shared Function InitLargeObject() As LargeObject
If 1 = Interlocked.Increment(instanceCount) Then
Throw New ApplicationException( _
"Lazy initialization function failed on thread " & _
Thread.CurrentThread.ManagedThreadId & ".")
End If
Return New LargeObject(Thread.CurrentThread.ManagedThreadId)
End Function
Shared Sub Main()
' The lazy initializer is created here. LargeObject is not created until the
' ThreadProc method executes.
lazyLargeObject = New Lazy(Of LargeObject)(AddressOf InitLargeObject, _
LazyThreadSafetyMode.PublicationOnly)
' Create and start 3 threads, passing the same blocking event to all of them.
Dim startingGate As New ManualResetEvent(False)
Dim threads() As Thread = { _
New Thread(AddressOf ThreadProc), _
New Thread(AddressOf ThreadProc), _
New Thread(AddressOf ThreadProc) _
}
For Each t As Thread In threads
t.Start(startingGate)
Next t
' Give all 3 threads time to start and wait, then release them all at once.
Thread.Sleep(50)
startingGate.Set()
' Wait for all 3 threads to finish. (The order doesn't matter.)
For Each t As Thread In threads
t.Join()
Next t
Console.WriteLine(vbCrLf & _
"Threads are complete. Running GC.Collect() to reclaim extra instances.")
GC.Collect()
' Allow time for garbage collection, which happens asynchronously.
Thread.Sleep(100)
Console.WriteLine(vbCrLf & "Note that only one instance of LargeObject was used.")
Console.WriteLine("Press Enter to end the program")
Console.ReadLine()
End Sub
Private Shared Sub ThreadProc(ByVal state As Object)
' Wait for the signal.
Dim waitForStart As ManualResetEvent = CType(state, ManualResetEvent)
waitForStart.WaitOne()
Dim large As LargeObject = Nothing
Try
large = lazyLargeObject.Value
' The following line introduces an artificial delay to exaggerate the race condition.
Thread.Sleep(5)
' IMPORTANT: Lazy initialization is thread-safe, but it doesn't protect the
' object after creation. You must lock the object before accessing it,
' unless the type is thread safe. (LargeObject is not thread safe.)
SyncLock large
large.Data(0) = Thread.CurrentThread.ManagedThreadId
Console.WriteLine( _
"LargeObject was initialized by thread {0}; last used by thread {1}.", _
large.InitializedBy, large.Data(0))
End SyncLock
Catch ex As ApplicationException
Console.WriteLine("ApplicationException: {0}", ex.Message)
End Try
End Sub
End Class
Friend Class LargeObject
Private initBy As Integer = -1
Public ReadOnly Property InitializedBy() As Integer
Get
Return initBy
End Get
End Property
Public Sub New(ByVal initializedBy As Integer)
initBy = initializedBy
Console.WriteLine("Constructor: Instance initializing on thread {0}", initBy)
End Sub
Protected Overrides Sub Finalize()
Console.WriteLine("Finalizer: Instance was initialized on {0}", initBy)
End Sub
Public Data(99999999) As Long
End Class
' This example produces output similar to the following:
'
'Constructor: Instance initializing on thread 4
'ApplicationException: Lazy initialization function failed on thread 3.
'Constructor: Instance initializing on thread 5
'LargeObject was initialized by thread 4; last used by thread 4.
'LargeObject was initialized by thread 4; last used by thread 5.
'
'Threads are complete. Running GC.Collect() to reclaim extra instances.
'Finalizer: Instance was initialized on 5
'
'Note that only one instance of LargeObject was used.
'Press Enter to end the program
'
'Finalizer: Instance was initialized on 4
'
注釈
Lazy<T> インスタンスのスレッド セーフ モードでは、複数のスレッドが Lazy<T> インスタンスを初期化しようとしたときの動作が記述されます。
mode
が LazyThreadSafetyMode.PublicationOnlyされていない限り、valueFactory
によってスローされる例外はキャッシュされます。 詳細については、Lazy<T> クラスまたは System.Threading.LazyThreadSafetyMode 列挙体を参照してください。
こちらもご覧ください
- 遅延初期化 の
適用対象
.NET