ある処理がスレッドセーフであるというとき……
- (A) 複数のスレッドから同時に処理を実行したときと、複数のスレッドが別々で処理を実行したときとで、処理結果が変わらないように設計されていること
- (B) あるスレッドで処理されている値が、別のスレッドから見えないようになっていること
(A)と(B)は重なる部分もあるんだけど、「スレッドセーフである」というライブラリで(B)にあたる処理を書く(書いてしまう)こともできるから、話をするときには注意したほうがいいですね。
ある処理がスレッドセーフであるというとき……
(A)と(B)は重なる部分もあるんだけど、「スレッドセーフである」というライブラリで(B)にあたる処理を書く(書いてしまう)こともできるから、話をするときには注意したほうがいいですね。
プロジェクトX見た。京の開発責任者で、その後富士通と道を違えた父が一切出ず、直属の上司や部下で、今も富士通との関わりが深い人たちのみが登場する内容には、家族としては非常に複雑な気持ちである。集合写真で真ん中でガッツポーズ決めてたのに。
— Takashi I (@DAHL_SAM) 2024年6月15日
なんでこんなことが起こるんだろう?というのを報道機関でなくエンジニアの側から考えたのだが、もしかして「知的財産やそれにまつわる情報の蓄積や引継ぎをちゃんとやってる事業会社」と「ドキュメンタリー」って非常に相性が悪いのでは?
スパコンの開発に伴う各種設計情報などの知的財産の引き継ぎがちゃんと行われている組織なら、事業会社内では知的財産としての管掌部署が現在も設定されているはず。ドキュメンタリーを作りたければまず報道機関から事業会社の広報部署に対して「あのプロジェクトのことを教えてください」というお願いが行くはずで、そうしたら広報部署は「あのプロジェクトには誰が関わっていたのか」よりも「あのプロジェクトの引取り先はどこか」(あのプロジェクトに対して責任を持って回答ができる管掌部署はどこか)という情報を出さないとマズいですよね。そういう聞かれ方をしたときに、管掌部署を差し置いて、単に昔そのプロジェクトに関わっていた人を「この人に聞いて」と紹介してしまったら、何のための管掌部署なの?という話になる。
また事業会社内の業務に対する評価がどうなっているか?もポイントだと思っていて、広報部署としては「外部からの問い合わせに対して、知的財産の管掌部署に正しく繋げることができた」ということが評価につながるしんだろうし、知的財産の管掌部署は「保持している知財に対して正しく対応が行えた、保持している知財を使って自社のPRに正しく寄与できた」ということは担当者の評価に繋げられる。一方で、その管理元部署から離れてしまった人は、稼動を割いて対応してもそのような評価には繋がらないんじゃないかな?
じゃぁ、報道機関側がそれを分かっていてどう情報を取りに行ったらいいだろう?と考える。営業情報の社外公開に関する規則はどういうわけだかクリアできたとして、まず確実に情報が残ってるのはプロジェクトに関わった人間のリストのはず。ISMSがあるから関係者の氏名リストはプロジェクトが終わっても保管されてるんじゃないかな。ただ、ISMSのリストだけでは座組みは分からない。座組みが知りたければプロジェクトの体制図を見る必要があるが、これはプロジェクト終了後に破棄されている可能性があるし、また素人が体制図を見ただけでは誰がキーマンなのかは分からない。というわけで、この方向からもプロジェクトのキーになっていた人はだれか?は外側から見ると非常に掴みにくいのでは。「開発責任者」というのがプロジェクトの体制のどこにいるのかは分からないけど、全体のとりまとめを行ったプロジェクトマネージャではないような言い方に見える(新規技術を大量に採用する大規模なプロジェクトで、技術的な取り纏めを行うエンジニアがプロジェクトマネージャを兼任していたら、とてもじゃないけどプロジェクトが回らないのでは)。
ところで会社によっては「社史」を作るという文化があって、実はこのようなケースがまさに「社史が役にたつケース」なのでは?と思い至った。たとえ後である人が会社を離れたとしても、社史を作った時点で社内にある程度以上の役職で残っていたなら、社史には名前が残るのでは?
-XX:StackYellowPages
に指定できる最小値は3(4kbページとして12kb)。
$ java -XX:StackYellowPages=1 Test1 intx StackYellowPages=1 is outside the allowed range [ 3 ... 8 ] Improperly specified VM option 'StackYellowPages=1' Error: Could not create the Java Virtual Machine. Error: A fatal exception has occurred. Program will exit.
ただ、Yellow Pagesを増やす必要のあるケースって何だろう? メソッド呼び出しでスタックの上に積めるのはメソッドの引数とローカル変数だけ(定数プールへの参照は微々たるもの)みたい。
なので、long型ローカル変数を3,000個用意したうえでスタックサイズを調節すれば12kbのページをぶっちぎってRed Pageに到達できるかと思って以下のようなプログラムを作ってみたんだけど、いずれも普通にjava.lang.StackOverflowError
が発生するんだよなぁ……
以下をPowerShellから138..150 | ForEach-Object { java -Xss"$_"k Test1 }
のようにして実行。
// javac -J-Xss4m Test1.java public class Test1 { public static void main(String args[]) { stackoverflow(1); } public static void stackoverflow(int i) { System.out.println(i); // & { $list = (1..5500); $list | ForEach-Object { "long i${_} = ${_};" }; "System.out.println(0"; $list | ForEach-Object { "+ i$_" }; ");" } | sv hoge; $hoge -join " " | Set-Clipboard long i1 = 1; long i2 = 2; long i3 = 3; long i4 = 4; long i5 = 5; long i6 = 6; long i7 = 7; ... stackoverflow(i+1); } }
PS C:\home\src> 138..150 | ForEach-Object { "■Xss:$_"; java -Xss"$_"k Test1 } ■Xss:138 1 15127750 Exception in thread "main" java.lang.StackOverflowError at Test1.stackoverflow(Test1.java:11) at Test1.main(Test1.java:4) ■Xss:139 1 15127750 Exception in thread "main" java.lang.StackOverflowError at Test1.stackoverflow(Test1.java:11) at Test1.main(Test1.java:4) ■Xss:140 1 15127750 Exception in thread "main" java.lang.StackOverflowError at Test1.stackoverflow(Test1.java:11) at Test1.main(Test1.java:4) ■Xss:141 1 15127750 Exception in thread "main" java.lang.StackOverflowError at Test1.stackoverflow(Test1.java:11) at Test1.main(Test1.java:4) ■Xss:142 1 15127750 Exception in thread "main" java.lang.StackOverflowError at Test1.stackoverflow(Test1.java:11) at Test1.main(Test1.java:4) ■Xss:143 1 15127750 Exception in thread "main" java.lang.StackOverflowError at Test1.stackoverflow(Test1.java:11) at Test1.main(Test1.java:4) ■Xss:144 1 15127750 Exception in thread "main" java.lang.StackOverflowError at Test1.stackoverflow(Test1.java:11) at Test1.main(Test1.java:4) ■Xss:145 1 15127750 Exception in thread "main" java.lang.StackOverflowError at Test1.stackoverflow(Test1.java:11) at Test1.main(Test1.java:4) ■Xss:146 1 15127750 Exception in thread "main" java.lang.StackOverflowError at Test1.stackoverflow(Test1.java:11) at Test1.main(Test1.java:4) ■Xss:147 1 15127750 Exception in thread "main" java.lang.StackOverflowError at Test1.stackoverflow(Test1.java:11) at Test1.main(Test1.java:4) ■Xss:148 1 15127750 Exception in thread "main" java.lang.StackOverflowError at Test1.stackoverflow(Test1.java:11) at Test1.main(Test1.java:4) ■Xss:149 1 15127750 Exception in thread "main" java.lang.StackOverflowError at Test1.stackoverflow(Test1.java:11) at Test1.main(Test1.java:4) ■Xss:150 1 15127750 Exception in thread "main" java.lang.StackOverflowError at Test1.stackoverflow(Test1.java:11) at Test1.main(Test1.java:4)
起動オプションの初期値は何か、最終的にどのような値が指定されたか、そのうちコマンドラインで渡した値は何か、は以下のオプションで表示できる。
-XX:+PrintFlagsFinal
: 最終的な設定値-XX:+PrintFlagsInitial
: 初期値-XX:+PrintCommandLineFlags
: コマンドライン上で与えた設定値java -XX:+PrintFlagsFinal -version
のようにして実行する。Windows TerminalのPowerShell上でシンタックスハイライトの表示がおかしくなるのが気になるならjava -XX:"+PrintFlagsFinal" -version
でもよい。version
オプションを先に指定してjava -version -XX:+PrintFlagsFinal
のようにすると表示されないので注意。
javac -J
のあとにオプションを指定する。たとえば2コンパイラでStackOverflowErrorが出たらjavac -J-Xss4m Test1.java
など。
開発時・性能問題調査時・本番環境で指定すべきオプションをわかりやすく指定している記事は以下。検討時のスタート地点として良さそう。
-XX:StackRedPages
、-XX:StackYellowPages
、-XX:StackShadowPages
については以下が分かりやすい。-XX:+PrintGC
Java8の-XX:+PrintGC
はJava11以降ではどう変わったのか?は以下にまとまっている。
そういやCOBOLはどうなんだっけ?ということで確認。 やっぱり除算は鬼門で、できるだけ乗算で処理できるように仕様を決めるのがベターということでしょうね。
IDENTIFICATION DIVISION. PROGRAM-ID. DECUMALTEST. DATA DIVISION. WORKING-STORAGE SECTION. 01 RESULT PIC 9(1)V9(37) VALUE 0.0. PROCEDURE DIVISION. INITIALIZE RESULT. COMPUTE RESULT = 0.1 + 0.1 + 0.1. DISPLAY "0.1 + 0.1 + 0.1 = "RESULT. IF RESULT = 0.3 THEN DISPLAY "0.1 + 0.1 + 0.1 IS EQUAL TO 0.3." ELSE DISPLAY "0.1 + 0.1 + 0.1 IS NOT EQUAL TO 0.3." END-IF. INITIALIZE RESULT. COMPUTE RESULT = 4.8 - 4.7 - 0.1. DISPLAY "4.8 - 4.7 - 0.1 = "RESULT. IF RESULT = 0.0 THEN DISPLAY "4.8 - 4.7 - 0.1 IS EQUAL TO 0.0." ELSE DISPLAY "4.8 - 4.7 - 0.1 IS NOT EQUAL TO 0.0." END-IF. INITIALIZE RESULT. COMPUTE RESULT = (1.0 / 3.0) * 3.0. DISPLAY "(1.0 / 3.0) * 3.0 = "RESULT. IF RESULT = 1.0 THEN DISPLAY "(1.0 / 3.0) * 3.0 IS EQUAL TO 1.0." ELSE DISPLAY "(1.0 / 3.0) * 3.0 IS NOT EQUAL TO 1.0." END-IF. STOP RUN.
0.1 + 0.1 + 0.1 = 0.3000000000000000000000000000000000000 0.1 + 0.1 + 0.1 IS EQUAL TO 0.3. 4.8 - 4.7 - 0.1 = 0.0000000000000000000000000000000000000 4.8 - 4.7 - 0.1 IS EQUAL TO 0.0. (1.0 / 3.0) * 3.0 = 0.9999999999999999999999999999999999999 (1.0 / 3.0) * 3.0 IS NOT EQUAL TO 1.0.