私の以前の記事を読んだ人は、私がゲーム開発を行っていることを知っているかもしれません。私のアイデアと出発点の多くはゲームのアイデアに従って処理されているため、Webとの対立があり、それに沿っていない可能性があります。
スレッドモデルをカスタマイズしたい理由を教えてください。
私が作成したMMORPGまたはMMORPGゲームによると、スレッドはメインスレッド、グローバル同期スレッド、チャットスレッド、チームスレッド、マップスレッド、マップメッセージの配布と配信スレッドに分割されます。
一部の列は、私の部門とデータフローに従って制御する必要があります。
ゲームサーバーで行うべき主なことは、プレーヤーのコマンドリクエスト - >対応する操作 - >結果を返すことです。
サーバー側のすべてのメッセージはメッセージマネージャーに登録され、メッセージが登録されているときにスレッドモデルが指定されます。
メッセージを処理のためにプレーヤーのマップスレッドに送信する必要がある場合、メッセージを登録するときは、スレッドモデル(マップメッセージの配布とディスパッチスレッド)を使用する必要があります。
最初にスレッドモデルを分析しましょう。
スレッドモデルコードを見る前に、まずタスクモデルを見ています
パッケージnet.sz.engine.thread; import java.io.serializable; Import org.apache.log4j.logger; Import net.sz.engine.structs.objectattribute; Import net.sz.engine.structs.objedglobal;/** *タスクモデル * * <br> 13882122019 <br> */public abstract class taskeventはシリアル化可能、クローン可能{private static final logger log = ogger.getLogger(taskevent.class); private static final long serialversionuid = 419602065994845804l; //ランタイムデータプライベート一時的な最終ObjectAttribute runother = new objectAttribute; //タスク作成時間保護された長いCreateTime; //タスク一意のID保護された長いTaskID; //キャンセルされたタスク保護されたboolean cancel = false; public Taskevent {this.runother.put( "submittime"、system.currenttimemillis); CreateTime = System.CurrentTimemillis;キャンセル= false; taskId = objectglobal.getuuid; } public long getCreatetime {return createTime; } public void setCreatetime(long createTime){this.createtime = createTime; } public long getSubmittime {return this.runother.getLongValue( "submittime"); } public ObjectTribute getRunother {return runother; } public boolean iscancel {return cancel; } public void setCancel(booleanキャンセル){this.cancel = cancel; } public abstract void run; @Overrideパブリックオブジェクトクローンは、cloneNotsupportedexceptionをスローします{return super.clone; //生成されたメソッドの本体を変更するには、ツールを選択します|テンプレート。 }}パッケージnet.sz.engine.thread;/** *タイマー執行者 * * * <br> *著者失敗プログラマー<br> *メール[email protected] <br> *電話13882122019 <br> */パブリックアブストラクトクラスティマルタスケブント拡張taskevent / ***実行を開始する時間*/保護された長い早い時刻。 / ***最初に1回実行するかどうか*/保護されたブールの起動。 / ***終了時間*/保護された長いエンドタイム。 / ***実行数*/保護されたint ActionCount; / ***インターバル実行時間*/保護されたintインターバルタイム。 / **** @param Starttime Stignify Start Time* @Param isStartAction開始時に1回実行するかどうか* @Param EndTimeの終了時間を指定* @param ActionCount実行数を指定* @param intervaltime intervalime time*/ public timertaskevent(long Startime、boolean is -startaction、int intercount、int action intercount、intccount、int action intercount、; this.starttime = starttime; this.startaction = isstartaction; this.endtime = endtime; this.actioncount = actioncount; this.intervaltime = intervaltime; } / ***タスクのスタート実行時間を指定** @param開始時刻を指定してくださいActionCount、intervaltime); } / ***指定された終了時間は終了時間であり、実行の数は必ずしも十分ではありません** @param isstartActionの最初に1回実行するかどうか* @paramの終了時間を指定するかどうか* @param ActionCount実行数を指定*これ(0、ISSTARTACTION、ENDTIME、ACTIONCOUNT、INTERVALTIME); } / ***開始時刻と終了時間を指定** @param開始時刻開始時間を指定* @param終了時間を指定* @param intervaltimeインターバルタイムを指定* / public timertaskevent(長い早い時刻、長期、int intervaltime){this(oratetime、false、endtime、-1、intervalime); } / ***指定された実行時間とインターバル時間** @param ActionCount実行数を指定* @param intervaltime間隔時間を指定* / public timertaskevent(int actioncount、int intervalime){this(0、false、0、actioncount、intervaltime); } / ***送信後の無制限の実行* @param intervaltime指定インターバル時間* / public timertaskevent(int intervaltime){this(0、false、0、-1、intervalime); } public long getstarttime {return starttime; } public void setStartTime(LONG STARTTIME){this.startTime = startTime; } public boolean isstartaction {return startaction; } public void setStartAction(boolean startaction){this.startaction = startaction; } public long getEndtime {return endtime; } public void setendtime(long endtime){this.endtime = endtime; } public int getActionCount {return ActionCount; } public void setActionCount(int ActionCount){this.actionCount = actionCount; } public int getIntervalTime {return intervaltime; } public void setintervaltime(int intervaltime){this.intervaltime = intervaltime; }}
タスクモデルとタイマータスクモデルは次のとおりです。
パッケージnet.sz.engine.thread; import java.util.arraylist; import java.util.list; import java.util.concurrent.concurrentlinkedqueue; import net.sz.engine.structs.objectglobal; Import net.sz.engine.utils.mailutil; intil.sz.Sz. org.apache.log4j.logger; import org.jboss.jandex.main;/** *スレッドモデル * <br> *著者失敗したプログラマー<br> *メール[email protected] <br> *電話13882122019 <br> */public class model {prival static final Logger = static static logger logger.getLogger(threadmodel.class); private static long threadid = 0;保護された静的最終オブジェクトsyn_object = new Object;保護された長いTID;保護された文字列名;保護された長いlastSendMail = 0;保護された最終配列<mythread>スレッド= new ArrayList <>; /***タスクリストスレッドセーフタスクリスト*///保護された最終リスト<TaskModel> taskqueue = new ArrayList <>;保護された最終的にconcurrentlinkedqueue <taskevent> taskqueue = new concurrentlinkedqueue <>; / ***/保護された最終リスト<Timertaskevent> Timerqueue = new ArrayList <>; // false Identity削除スレッド保護された揮発性ブールンrunning = true; public StreadModel(ThreadGroup Group){this(group、 "No Name"、1); } public threadmodel(string name){this(threadpool.unknownthreadgroup、name、1); } public threadmodel(threadgroupグループ、文字列名、int threadcount){this(group、name、threadcount、null); } public threadmodel(threadgroupグループ、文字列名、int threadcount、runnable runnable){synchronized(syn_object){threadid ++; tid = threadid; } for(int i = 1; i <= threadcount; i ++){mythread thread; if(runnable == null){tid、group、this、name + " - " + tid + " - " + i);} } thread.start; threads.add(thread); } this.name = name; } / ** *スレッド名 * * @return * / public string getName {return name; } / ** *スレッドのカスタムIDを取得 * * @return * / public long getId {return this.tid; } / ** *新しいタスクごとに新しいタスクを追加するには、タスクキューを目覚める必要があります * * @param runnable * / public void addtask(taskevent runnable){taskqueue.add(runnable);同期(taskqueue){/ *キューを起動して実行を開始 */ taskqueue.notifyall; }}/** *スレッドにタイマータスクを追加 * * @param runnable */public void addtimer(timertaskevent runnable){synchronized(timerqueue){if(runing){//最初に1回実行(runnable.startaction){addtask(runnable); } timerqueue.add(runnable);} else {log.error( "スレッドは停止しました"); }}}} // <editor-fold defaultState = "collapsed" desc = "タイマースレッドエグゼキューターpublic void timerrun"> / ***タイマースレッドエグゼキューター* / public void timerrun {arraylist <timertaskevent> taskmodels;同期(Timerqueue){//キューが空でない場合は、キュータイマータスクモデル= new ArrayList <>(TimerQueue)を取り出します。 } if(!taskmodels.isempty){for(timertaskevent timerevent:taskmodels){int execcount = timerevent.getrunother.getTinValue( "execcount"); long lasttime = timerevent.getrunother.getLongValue( "lastexectime"); long nowtime = system.currenttimemillis; if(lasttime == 0){timerevent.getrunother.put( "lastexectime"、nowtime);} else if(timerevent.iscancel){//タスクがキャンセルされた場合(Timerqueue){Timerqueue.Remove(Timerevent); } log.debug( "タイマータスクのクリーン:" + timerevent.getClass.getName);} else if(nowtime> timerevent.getStartTime //開始時間が満たされているかどうかTimerevent.getEndtime)//終了時間&&(Nowtime -LastTime> = Timerevent.getInterValtime))//最後の実行以来、インターバル時間が満たされているかどうかを判断します。 execCount); Timerevent.getRunother.put( "lastexectime"、nowtime); nowtime = system.currenttimemillis; //削除状態を決定するif((timerevent.getendtime> 0 && nowtime.getEndtime)||(timerevent.getActionCount> 0 && timerevent.getActionCount <execuount) Timerqueue.Remove(TimereVent); } log.debug( "クリーニングタイマータスク:" + timerevent.getClass.getName); }}}}}}} // </editor-fold> // <editor fold defaultState = "collapsed" desc = "view swreet showStacktrace">/****ビュースレッドスタック*/public void showStacktrace {StringBuilder buf = New StringBuilder; for(mythread currentthread:swreet){long procc = system.currenttimemillis -currentthread.getLastexecutetime; if(procc> 5 * 1000 && procc <86400000l){// 10日未満// stuck-> ").append(procc/1000f).append(" s/n ").append(" execute task: ")。 .Append(Elements [i] .getClassName).Append( "。").append(elements [i] .getMethodName).Append( "(")。付録(要素[i] .getFileName).append( ";")。 }} catch(例外e){buf.append(e); } buf.append( "/n ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ }} string toString = buf.toString; if(!stringutil.isnullorempty(toString)){log.Error(toString); if(system.currenttimemillis-lastSendmail> 5 * 60 * 1000){lastSendmail = system.currenttimemillis; mailutil.sendmail( "stuck-> gameid-> gameid-> fameid-> famed-" + " +" + " +" + " ObjectGlobal.Platform + "Server ID-" + objectGlobal.Serverid、ToString); }}} // </editor fold> @override public void run {mythread currentthread =(mythread)thread.currentthread; while(runing){while(taskqueue.isempty && running){try {/*タスクキューは空です。新しいタスクは、新しいタスクが参加して目が覚めるのを待っています*/同期(taskqueue){taskqueue.wait(500); }} catch(arturnedexception ie){log.error(ie); }}/*タスクを取得して実行します*/if(runing){currentThread.lastCommand = null; currentThread.lastCommand = taskqueue.poll; } if(currentThread.lastCommand!= null){if(currentThread.lastCommand.iscancel){//タスクがキャンセルされた場合。 }/*タスクを実行* /// r.setsubmittimel; currentthread.lastexecutetime = system.currenttimemillis; try {currentthread.lastcommand.run;} catch(Exception e){log.Error( "Worker <" " + currentThread.getName +"エラーが発生しました: "、e); } long timel1 = system.currenttimemillis -currentthread.lastexecutetime; if(timel1 <= 20){} else if(timel1 <= 100l){log.info( "worker <" " + currentthread.getName +" ">タスクを完了しました:" + currentThread.lastCommand.toString + "実行時間:" + Timel1); "">タスクの完了の長期実行: " + currentThread.lastCommand.toString +" "タスクスクリプトロジック時間消費:" + timel1);} else {log.info( "worker <" " + currentthread.getName +" "タスクスクリプト時間消費: " + Timel1); } currentthread.lastexecutetime = 0; }} log.Error( "スレッドエンド、ワーカー<" " + swerch.currentthread.getName +" "> exit"); } / ***カスタムスレッド* /パブリッククラスMythread拡張スレッド{ / **** @param TidカスタムスレッドID* @Paramグループグループ* @param Nameスレッド名* /パブリックマイスレッド(スレッドグループグループ、実行可能な実行、文字列名){スーパー(グループ、ラン、ラン、名前); } //スレッドパブリックロング_idのカスタムID; //実行タスクPublic Volatile Taskevent LastCommand; //タスクの実行を開始する時間public public volatile logeexcutetime = 0; Public Taskevent getLastCommand {return lastCommand; } public long getLastExecutetime {return lastexecutetime; } / ** * return thread custom id * * @return * / @override public long getid {return _id; }} / ***スレッドを停止し、スレッドの停止状態を設定すると、スレッドがすぐに終了しません* / public void stop {this.runing = false; } public boolean isruning {return running; } @Override public String toString {return "スレッド{" + "tid =" + tid + "、name =" + this.getName + '}'; }}
ThreadModelから構築しました
public ThreadModel(ThreadGroupグループ、文字列名、int threadCount、runnable runnable){synchronized(syn_object){threadid ++; tid = threadid; } for(int i = 1; i <= threadcount; i ++){mythread thread; if(runnable == null){tid、group、this、name + " - " + tid + " - " + i);} } thread.start; threads.add(thread); } this.name = name; }ご覧のとおり、ここでは宣言されたmythreadスレッドクラスを実行します
なぜ私はこれについて考えるのですか?たとえば、共有データやスレッドのクリティカルエリア処理フローなど、ログ作成データを処理している場合、nスレッドを使用してそのような作業を処理することを検討できます。汚れたデータは生成されません。
チームを組んでスキルキャストを要求したい場合は、単一のキューを処理する必要があります。スレッドモデルには1つのMythReadだけが必要です。これは、ロックに依存しなくなったデータとスレッドクリティカル領域を共有する問題を解決するために、ブロッキングモードのシリアル実行(またはキューの実行)としてカウントされません。
私はとても醜いです、私を許してください
上の写真に示すように、各スレッドモデルに2つのキューがあり、1つのタイムテスケブントともう1つのTaskVentがあり、グローバルタイマースレッドがあります。
グローバルタイマースレッドの機能は、スレッドモデルのTimetaskeventを処理して実行する必要があることを確認することであるため、TaskVentチームに追加されます。最終実行はTaskVentキューです
Timetaskeventを対応するスレッドモデルに保存する必要があるのはなぜですか?それは、たとえば、私のスレッドA(スレッドモデルインスタンス)が一定期間実行された後、リソースを閉じて解放する必要があるため、対応するタイムテスクを見つけて削除する必要があるためです。
パッケージnet.sz.engine.thread; Import java.util.hashmap; Import java.util.map;/** * * <br> *著者落下プログラマ<br> *メール[email protected] <br> *電話13882122019 <br> public TimerThread {super(threadpool.globlthreadgroup、 "グローバルタイマースレッド"); } @Override public void run {while(true){synchronized(syn_object){try {syn_object.wait(2);} catch(arturtedexception ex {}} hashmap <long、long、hashmap = hashmap = new hashmap <>(swrewpool.getthreadmap); hashmap.entryset){long key = entryset.getKey; swreetmodel value = entryset.getValue; value.timerrun; }}}}
スレッドモデルマネージャー
パッケージnet.sz.engine.thread; Import java.util.hashmap; Import java.util.concurrent.concurrenthashmap; Import net.sz.engine.script.manager.scriptmanager; Import net.sz.engine.timer.globtimervent org.apache.log4j.logger;/** *スレッドマネージャー * * * <br> *著者失敗プログラマー<br> *メール[email protected] <br> *電話13882122019 <br> */public class threadpool {静的プライベート最終ロガーlog = getlogger(threadpool.class);静的なパブリックファイナルロンググロブストレッド。静的なプライベート最終Timerthreadglobltimerthread;静的な最終checkthreadtimerthreadmodel;静的パブリックファイナルスレッドグループGloblThreadGroup = new StreadGroup( "Global StreadGroup"); static public final threadgroup nown nouctthreadgroup = new ThreadGroup(globlthreadgroup、 "不明なスレッドグループ");静的なプライベート最終的なCONCURRENTHASHMAP <LONG、STHREADMODEL> threadMap = new ConcurrentHashmap <>; public static void main(string [] args){threadpool.addtimertask(globlthread、new timertaskevent(1000){@overridepublic void run {log.error( "sssss");}}); } static {//グローバルスレッドを作成しますgloblthread = addthreadmodel(globlthreadgroup、 "globlthread"); //指定されたタスクタイミングを実行して、足音addtimertask(globlthread、new globtimerevent(scriptmanager.getinstance.getBaseScriptEntry))をトリガーします。 //サーバー消費タイミングモデルAddTimerTask(GloBlThread、new PrintlnserverMemoryTimerevent)をクエリします。 //タイマースレッドGloBltimerThread = new TimerThreadを作成します。 globltimerthread.start; //スレッドをチェックしてくださいCheckThreadTimerthReadModel = addThreadModel(GloblThreadGroup、 "SthreadTimer Eventを確認"); addtimertask(checkthreadtimerthreadmodel、new checkthreadtimerevent); } / ** *指定されたIDスレッドモデルを削除する場合、ステータスを停止状態に設定しますif(remoot!= null){remove.stop; } removeを返します。 } / ** *スレッドプールですべてのスレッドを取得 * * @return * / static public concurrenthashmap <long、swreetmodel> getthreadmap {return threadmap; } / ** *スレッドプールでスレッドを取得 * * @param threadid * @return * / static public threadmodel getthreadmodel(long threadid){threadmodel get = threadmap.get(threadid); if(get == null){log.error( "スレッドモデルは見つかりません:" + threadid、new Exception( "スレッドモデルは見つかりません:" + threadid)); } return get; } / ** *スレッドをスレッドプールに登録します * <br> *デフォルトのグループ化不明のgraw wuntsgroup * * @param name name * @return * / static public long addthreadmodel(string name){return addthreadmodel(unknownthreadgroup、name); } / ** *スレッドをスレッドプールに登録します * <br> *デフォルトのグループ化不明のthreadgroup * * @param name threadname * @param threadcount threadcount * @return * / static public long addthreadmodel(int、int threadcount){return addthreadmodel(unknowedthreadgroup、name、name、name、name); } / ***スレッドをスレッドプールで登録** @paramグループスレッドグループ化情報* @param名スレッド名* @return* / static public long addthreadmodel(threadgroupグループ、文字列名){return addthreadmodel(group、name、1); } / ***スレッドをスレッドプールで登録** @paramグループスレッドグループ化情報* @param nameスレッド名* @paramスレッドカウントスレッドカウント* @return* / static public public long addthreadmodel(string name、int threadcount){return addthreadmodel(グループ、名前、null、null、null、null、null、null、null、null、null、null、 } / ***スレッドをスレッドプールで登録** @paramグループスレッドグループ情報* @param名スレッド名* @param runnable* @param threadcount threadcount* @return* / static public addThreadmodel(スレッドグラウムグループ、文字列名、実行可能な実行可能、intwershcount) addthreadmodel(threadmodel)を返します。 } / ** *スレッドをスレッドプールで登録 * * @param threadmodel * / static public addthreadmodel(threadmodel threadmodel){threadmap.put(threadmodel.getid、swreetmodel); return threadmodel.getId; } / ** *タスクを追加 * * @param threadid * @param task * @return * / static public boolean addtask(long threadid、taskevent task){threadmodel threadmodel = getthreadModel(swreetID); if(threadModel!= null){threadmodel.addtask(task); return true; } falseを返します。 } / ** *タイマータスクの追加 * * @param threadid * @param task * @return * / static public boolean addtimertask(long threadid、timertaskevent task){threadmodel threadmodel = getthreadmodel(threadid); if(threadModel!= null){shoodmodel.addtimer(task); return true; } falseを返します。 } / ** *タスクを追加し、現在のスレッドにタスクを追加 * * @param task * @return * / static public boolean addcurrentthreadtask(taskevent task){thread currentthread = shood.currentthread; if(currentThread Instance of SthreadModel.mythread){long threadId = currentThread.getId; swreetModel threadModel = getThreadModel(threadId); if(swreetModel!= null){shoodmodel.addtask(task); return true; }} falseを返します。 } / ** *タイマータスクを追加し、現在のスレッドにタスクを追加 * * @param task * @return * / static public boolean addcurrentthreadtimertask(timertaskeventタスク){thread currentthread = whresd.currentthread; if(currentThread Instance of SthreadModel.mythread){long threadid = currentThread.getId; swreetModel threadModel = getThreadModel(threadID); if(threadmodel!= null){shoodmodel.addtimer(task); return true; }} falseを返します。 }}
次に、使用法を見てみましょう
前の記事のスレッド紹介コード
public static void main(string [] args)arturtedexception {//スレッド並列性、複数のスレッドが複数のタスク/関数を実行しますnew shood(new run1).start;新しいスレッド(new run2).start; } // task1 static class run1を実装してrunnable {@override public void run {//タスク1 run1; //タスク3 run3を実行します。 }} // task2 static class run2を実装してrunnable {@override public void run {//タスク3 run3; //タスク1 run1; //タスク2 run2を実行する実行}} //タスク1 public static void run1 {system.out.println( "run1->" + system.currenttimemillis); } //タスク2 public static void run2 {system.out.println( "run2->" + system.currenttimemillis); } //タスク3 public static void run3 {system.out.println( "run3->" + system.currenttimemillis); }コードをモードに切り替えました
public static void main(string [] args)arturtedexception {//スレッドは並列であり、複数のスレッドが複数のタスク/関数long test1 = threadpool.addthreadmodel( "testshread-1"); long test2 = threadpool.addthreadmodel( "test thread-2"); //タスクthreadpool.addtask(test1、new run1)を追加します。 threadpool.addtask(test2、new run2); //タイマータスクThreadPool.AddTimerTask(TEST1、新しいTimerrun1)を追加します。 ThreadPool.Addtimertask(test2、new Timerrun2); } // task1 static class run1 extends taskevent {@override public void run {//タスク1 run1; //タスク3 run3を実行する}} // task1 static class timerrun1 extends timertaskevent {public timerrun1 {super(500); // 500ms linmited execution} @override public void run {//タスク1 run1; //タスク3 run3を実行する}} // task2 static class run2 extends taskevent {@override public void run {//タスク3 run3; //タスク1 run1; //タスク2 run2を実行する実行}} // task2 static class timerrun2 extends timertaskevent {public timerrun2 {super(500); // 500ms linmited execution} @override public void run {//タスク3 run3; //タスク1 run1; //実行タスク2 run2;を実行する}} // task1 public static void run1 {system.out.println( "run1->" + system.currenttimemillis); } // task2 public static void run2 {system.out.println( "run2->" + system.currenttimemillis); } //タスク3 public static void run3 {system.out.println( "run3->" + system.currenttimemillis); }次に、実行効果を見てみましょう
run1-> 1472120543013RUN3-> 1472120543013RUN3-> 1472120543017RUN1-> 1472120543017RUN2-> 14721205 43017RUN1-> 1472120543517RUN3-> 1472120543517RUN2-> 1472120543517RUN1-> 14721205444018RUN3-> 1477 2120544018RUN2-> 1472120544018RUN1-> 147212054520RUN3-> 147212054520RUN2-> 1472120544520RUN1 - > 1472120545021RUN3-> 1472120545021RUN2-> 1472120545021RUN1-> 1472120545521RUN3-> 1472120545521
すべてが正常です。
これは私のカスタムスレッドモデルです。
この時点で、カスタムスレッドモデルが完了しました。
では、利点と短所は何ですか?
利点は、現在の実行状況や、監視とタスクタイマーの実行だけでなく、現在の実行状況を含むデータフロー制御が非常に明確であることです。
短所、このカスタムスレッドモデルは、スレッドデータセキュリティとクリティカルエリアの問題を解決することはできません。また、適切な時期にロックまたは他のフォームで解決する必要があります。
偉大な神々が欠点を指摘することを願っています。そうすれば、すぐに修正できることを願っています。