概要
Thread-Specific Storageパターン
詳細
スレッドの入り口は1つでも、内部で固有領域が用意されておりスレッドごとに
別々に保存・取得するパターンです。
別名
・Per-Thread Attribute
・Thread-Specific Data
・Thread-Specific Field
・Thread-Local Strage
などと呼びます。
注意点
・スレッド固有の情報をスレッド外に保持することをthread-externalという
・スレッド固有の情報をスレッド内に保持することをthread-internalという
・Thread-Specific Storageパターンは他スレッドの影響を受けない。そのため排他の仕組みを考える必要がない
・このパターンは事情があり、変更出来ないクラスをマルチスレッド対応したい場合などに有効
構成
・Client:依頼者
・TSObjectProxy:スレッド固有なオブジェクトの代理人
・TSObjectCollection:スレッド固有なオブジェクトの集まり
・TSObject:スレッド固有なオブジェクト
サンプル
仕様
あるWebサイトに設定されているユーザー単位のアクセスカウンタを想定。
1ユーザーが何度も同じページにアクセスすると、そのユーザーのアクセス数のみがインクリメントされます。
構成
・Client:サイト利用ユーザー=User
・TSObjectProxy:Webサイト=WebSite
・TSObjectCollection:アクセスカウンタ群=AccessCounters
・TSObject:アクセスカウンタ=AccessCounter
ソースコード
# encoding: utf-8 require "pp" require "thread" def random_sleep sleep ((rand 10) + 1) * 0.05 end class User < Thread def initialize(name) block = lambda { puts "#{name} start" @name = name (1..10).each do |count| WebSite.access access_count = WebSite.access_count puts "#{name}'s access_count = #{access_count}" random_sleep end puts "#{name} end" } super(&block) end end class AccessCounters attr_accessor :threads def initialize @threads = {} end def get @threads[Thread.current.object_id] end def set(access_counter) id = Thread.current.object_id @threads[id] = AccessCounter.new end end class AccessCounter attr_accessor :count def initialize @count = 1 end def access @count += 1 end def access_count return @count end end class WebSite @@access_counters = AccessCounters.new class << self def access get_access_counter.access end def access_count get_access_counter.access_count end private def get_access_counter access_counter = @@access_counters.get if access_counter.nil? access_counter = AccessCounter.new @@access_counters.set access_counter end access_counter end end end threads = [] threads << User.new("hoge") threads << User.new("hige") threads << User.new("hage") threads.each {|t|t.join}
出力結果
hoge start hoge's access_count = 1 hige start hige's access_count = 1 hage start hage's access_count = 1 hage's access_count = 2 hoge's access_count = 2 hige's access_count = 2 hage's access_count = 3 hage's access_count = 4 hige's access_count = 3 hoge's access_count = 3 hage's access_count = 5 hige's access_count = 4 hoge's access_count = 4 hoge's access_count = 5 hige's access_count = 5 hage's access_count = 6 hoge's access_count = 6 hige's access_count = 6 hige's access_count = 7 hoge's access_count = 7 hage's access_count = 7 hoge's access_count = 8 hige's access_count = 8 hige's access_count = 9 hage's access_count = 8 hige's access_count = 10 hoge's access_count = 9 hoge's access_count = 10 hage's access_count = 9 hoge end hige end hage's access_count = 10 hage end