これは、多くの質問に答えて言うことです。フレームワークの (管理された) ソース コードが利用可能であることを忘れないでください。このツールを使用してすべてを取得できます: http://www.codeplex.com/NetMassDownloader
残念ながら、この特定のケースでは、多くの実装がネイティブ コードで行われているため、それを見ることはできません...
ただし、タイマーごとのスレッドではなく、プールスレッドを使用することは間違いありません。
タイマーの大きなコレクションを実装する標準的な方法 (これはカーネルが内部で行う方法であり、タイマーの大きなコレクションが間接的にどのように終了するかであると思われます) は、有効期限までの時間で並べ替えられたリストを維持することです。システムは、リスト全体ではなく、期限切れになる次のタイマーをチェックすることだけを心配する必要があります。
大まかに言えば、これにより、タイマーを開始するための O(log n) と、実行中のタイマーを処理するための O(1) が得られます。
編集: Jeff Richter の本を見ているところです。彼は、(Threading.Timer について) すべての Timer オブジェクトに対して単一のスレッドを使用すると述べています。このスレッドは、次のタイマー (つまり、上記のように) の期限を認識しており、必要に応じてコールバックのために ThreadPool.QueueUserWorkItem を呼び出します。これには、次の期限が来る前にタイマーで 1 つのコールバックのサービスを終了しない場合、そのコールバックが別のプール スレッドで再入力されるという効果があります。要約すると、多くのタイマーを使用することで大きな問題が発生することはないと思いますが、多数のタイマーが同じタイマーで起動したり、コールバックの実行が遅い場合は、スレッド プールが枯渇する可能性があります。