From b110dcf1aecdce457e3bdbdaf4bcb7c81e70bd05 Mon Sep 17 00:00:00 2001 From: fybug <1006291762@qq.com> Date: Thu, 13 Feb 2025 22:54:44 +0800 Subject: [PATCH 1/2] =?UTF-8?q?=E4=BF=AE=E6=AD=A3=E9=A1=B9=E7=9B=AE?= =?UTF-8?q?=E6=9E=B6=E6=9E=84=EF=BC=8Ctrylock=E7=8E=B0=E5=9C=A8=E6=98=AF?= =?UTF-8?q?=E5=B0=9D=E8=AF=95=E8=8E=B7=E5=8F=96=E8=80=8C=E4=B8=8D=E6=98=AF?= =?UTF-8?q?=E6=8A=9B=E5=87=BA=E5=BC=82=E5=B8=B8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- build.gradle | 17 +- jar/PDConcurrent_bin.jar | Bin 14946 -> 21042 bytes jar/PDConcurrent_sources.jar | Bin 11929 -> 18618 bytes .../java/fybug/nulll/pdconcurrent/SyLock.java | 525 +----------------- .../fybug/nulll/pdconcurrent/e/LockType.java | 8 +- .../nulll/pdconcurrent/fun/tryConsumer.java | 2 + .../nulll/pdconcurrent/fun/tryFunction.java | 3 + .../nulll/pdconcurrent/fun/tryRunnable.java | 1 + .../nulll/pdconcurrent/fun/trySupplier.java | 4 + .../nulll/pdconcurrent/i/AbstractSyLock.java | 216 +++++++ .../java/fybug/nulll/pdconcurrent/i/Lock.java | 140 +++++ .../nulll/pdconcurrent/i/ReadWriteLock.java | 203 +++++++ .../fybug/nulll/pdconcurrent/i/TryLock.java | 142 +++++ .../pdconcurrent/i/TryReadWriteLock.java | 204 +++++++ .../nulll/pdconcurrent/i/package-info.java | 9 + .../pdconcurrent/{ => lock}/ObjLock.java | 56 +- .../nulll/pdconcurrent/{ => lock}/RWLock.java | 335 ++++++----- .../nulll/pdconcurrent/{ => lock}/ReLock.java | 122 ++-- .../nulll/pdconcurrent/lock/package-info.java | 8 + .../nulll/pdconcurrent/package-info.java | 2 +- 20 files changed, 1256 insertions(+), 741 deletions(-) create mode 100644 src/main/java/fybug/nulll/pdconcurrent/i/AbstractSyLock.java create mode 100644 src/main/java/fybug/nulll/pdconcurrent/i/Lock.java create mode 100644 src/main/java/fybug/nulll/pdconcurrent/i/ReadWriteLock.java create mode 100644 src/main/java/fybug/nulll/pdconcurrent/i/TryLock.java create mode 100644 src/main/java/fybug/nulll/pdconcurrent/i/TryReadWriteLock.java create mode 100644 src/main/java/fybug/nulll/pdconcurrent/i/package-info.java rename src/main/java/fybug/nulll/pdconcurrent/{ => lock}/ObjLock.java (70%) rename src/main/java/fybug/nulll/pdconcurrent/{ => lock}/RWLock.java (42%) rename src/main/java/fybug/nulll/pdconcurrent/{ => lock}/ReLock.java (50%) create mode 100644 src/main/java/fybug/nulll/pdconcurrent/lock/package-info.java diff --git a/build.gradle b/build.gradle index bceb435..7b26077 100644 --- a/build.gradle +++ b/build.gradle @@ -53,12 +53,12 @@ dependencies { // lombok testCompileOnly "org.projectlombok:lombok:+" testAnnotationProcessor "org.projectlombok:lombok:+" - testRuntimeOnly 'org.junit.platform:junit-platform-launcher' + testRuntimeOnly "org.junit.jupiter:junit-jupiter:5.12.0+" } test { dependencies { - testImplementation "org.junit.platform:junit-platform-launcher" + testImplementation "org.junit.jupiter:junit-jupiter:5.12.0+" } useJUnitPlatform() } @@ -83,7 +83,7 @@ tasks.withType(Jar).configureEach { /** 编译包 */ tasks.register('PDConcurrent_bin', Jar) { archiveFileName = 'PDConcurrent_bin.jar' - archiveClassifier = '' + archiveClassifier = 'bin' // 打包编译输出 from sourceSets.main.output } @@ -96,17 +96,6 @@ tasks.register('PDConcurrent_sources', Jar) { from sourceSets.main.allSource } -//tasks.register('PDConcurrent_all', Jar) { -// archiveFileName = 'PDConcurrent_all.jar' -// archiveClassifier = 'all' -// // 打包编译输出 -// from sourceSets.main.output -// from { -// // implementation 相关的引入解压并打包入新的jar中 -// configurations.runtimeClasspath.collect { it.isDirectory() ? it : zipTree(it) } -// } -//} - tasks.register('release') { dependsOn PDConcurrent_bin dependsOn PDConcurrent_sources diff --git a/jar/PDConcurrent_bin.jar b/jar/PDConcurrent_bin.jar index b8cac15ec28adeb50b1b857d8b05d8a9bfd79d90..7c201907b4d9571e7718389e537db8c357499f93 100644 GIT binary patch literal 21042 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 z zm!vaD4^DTCJhH5asJk1H4^(&DP6BxSnz=y0jewK)P}lhwld(;Mi$wTbVyj~>G)L#^ z9}iF2w4n3XJ%i8=XtxL=^dxpC=GBpWX}7q{FX!BRA={y810n} zVM!3T2NM!~y)Aq%sm({N_61(7fu~3jgSo|oB5O4cvm_SPVm4?1G)kh}RipqOvHfZF2V z6#5OzE_OHDg97D8I@l4;5Qjp0U2a<#OlioN22||OWk~#*!f7{VlS zxoneDs7mQ6aKof#Z!=i~h(j#;!;?FtFR7!rg(&_6pSFgG`4w8*&Ck!v+}vm`rHZH1 zcKZC=1>9?tvLn=w?rAfKt6MJhj~}cj7X^rJ->*oe@<(X$lVgkBwv`?rD@g01QrP@5 ziPa^+r6zm^k~F3RJ-CP~-ZR*TufBy0!pl#b z*G*`Sw6TF3rhP^YIsso^eSj}-f+>()Y_Pn^17CJzpEQ^9D0|w0xW-;AmA^r+OF*|+ z+bLmYECQZy|F47D8i&@mw|`Hy`(XU9Ho5BmA?k&yZ>~zJm>Z;w@!}+``}_hhSE7Dg zeme^qocJ-oAA-RUB>4U){UhU$G^y+2rZzdHDw>w%&n0=Na25+ZJqAi8KTuY~7QzM& zbhl@fKmHutK|Qddx2+$or>Anp2OW)$W;jliAk<5xgs?P%LdhucD=~bSn z=F#q6jET(vGgNO=^F&X`loyq`G6W~`sSqHUOb7bB6Z@7tJi+V_b=vC+Kq|X}*ZVg5 zPL@oD3idFUrU#+k`!`R7!WPh@{7?`Ic@-((U+FY> z1XS7R9R8|uqE~9Fp1~7KQ#*Sa}NrRH?Q$8mb z{mq|X$jV|xOV#&CuMzRcd%(L8sQmXx0+r~~8X)}=Qb|EOU!Qsr@&35Kqo=5SH!YDb zZX;*MhpQ(=t`A`?@(F@+?}8s5w_gx25!gm7$IP!JtiIHv&uv2Alg1XmL1vW_=)q-G zPzfSH7EhMWWF-P8KZ{h@X2TFNo(|Svu?#lo0PkwqIAS8;Ub7aa(bjYRtF|s({Q=9x+7Ecwg;Yd0s!hj4?1$tse<RE{Y69o}HK}n44`EGSl_9Jr>GzQuZKKs^+!N`PW zilAyUH~zMY5QOGDU}{oP_VhJ#hZs_kPXn|0ApDqE8rP7m]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 diff --git a/jar/PDConcurrent_sources.jar b/jar/PDConcurrent_sources.jar index faaffcee6bc8121a4c9264a801a03ab9485cee1a..e3154d1e5af5524fde7b237cd5877ad67a2b35db 100644 GIT binary patch literal 18618 zcmb{a1yo(jvIYv{PH^`GcLD?t?hXsL;O_3Qa0%}2?k>SCxLeSm!QJh#&-wq8>~nLo z?;GPyMk8Z%ebnq(v%0#fz9lCK4uK8=0s{kL+#szE@_K>&_3ib7eI3%m0Dd}g84(6> z5V^li%riNi*n6Eo2nqu7D*kh#G{20vh_E7nURp#tlHUxB2|e%z+&)N?c#wT1?r?uZ zPNWPS;)co9>>CR+Y4RJwtcm#i39ZEZItn>%IS6Zc0^ydYjvMdClL$Ok@ZB?rGR1h^ zBGDN3eKraAWu5md8ZxOIE8gYTnH|$cH`P4+A<*Y2k>e=Vucf(qWaD&tJ5!uRV;K!lgk3g(|>)#GNpXRvynyqNJ% z8*n<4gJnF<(sa?`5;0wB@SoSD^#M4^T!nCP($?y+(A&7t8e=v=FFv`M-|_obh%=Cw z;`dDw{ahMOpqbq3YW!ynpFup$Apw~h9XHh9@eRF`TjUm06u9Gf} znADhzl&q3isT8&J{4mYv;NT>UnE2SZBt0Fq#3;?AWc|+e#`e_w)W){LghJIIV~smU z{@GpsitMiA!Qv0_W@6i_G(kO6aS<<+UdmuGH8XizBd-jgZ-#FMiBJ(cGXsYb2?j~t z_^^^(N?dI6$Z&j$N=oT^Y-SpPf?8CG9AcajhRv9Mg_9E zvEbb^4i_M&8ja_|giCeGmQEc`W+=GsGaTumCEC`eFD%Rs!nVVFsWYY5t}VuJv*?R3 zgYS=0bq=k)tDQ%~0ttiPXFbU}v4F($WX^&)!z^@pJ%4;2Tm7P0|3&kc*NVW7Qazz) zu*~#zwSljL_Rp(sqpNSOYivkoYGq{oua%$v|1GJ@2kW_5f`^RjI-tuZl%U?JnDEE9 z0d+%pQx5;jYIgQ<@G>;l6;ZNQLQt9)8H2>k?ru~6`#}a^=On76#Kz{TM8zPelqH%W z{-Sc^ zPilfuWgi(-`1S0Z^xUX>k=wpZrKRDw0pkps^xEpCxXu6TzR6atK)=4e9Gl=EAawtv zx`UmoptY5~qotwUzn)dSVpk{{KXM!NInuUUGQ^QquZA8>Ffb8AuhTxikYaB|=4wKV zK#LS>G8S4^n>!fmy zmtbHcgAztPQM5LF@QpJNZ8;03Od3dLF1e9SMl?4hJcaR%ic`c_D4{x=K-5qZo3(}i zTh^o@d0$Niftemd1YIH5=fm$d3nyL31+1K!JuV-8Pu4!3ta>#+-WuIJUqvG6FpM)e zWv-Gbkn63-J1#1Td>Fb@1&`>BZb~GnM0Yr93?|1hMtOha1%~v{wpS}RFXQ@xPhhHk zzd*cP@#nP1ZE(!wqu z11;_7^Ldu6E}26pNoB14^z?@zP;bvjEL~GS+jdbqvmsZ?wwM|rQ1MnnP;A>HzbMHm zRl;A5*i5f1CzAgdmrq5`0LF^P=W@EU65mG=A0M=5WsuN+3EfO;YsQ-IA`xw&79N3d49v@bqvYsLV(5$2bIK3t!32@JwnN7p z32t7{pPs+x^;H-(NCKUHHHqH;qe+N3TIoBOT3h|gB=TcABG8zS`ya$ygT9+My|Xz+ zo+T5CMiyfULVqhS`=vI7A!7bKlh5A-8Gz0*VKcRd>sG|SVF)vzzh3Vw>(2*1g*nH@ zJMOXO!g@|N20Ju5GM;>{AW;CXO?CX4WLtG_HfsrmMhgeJut{VmJ*s{ry$HQ^4Ik_h zzCma+DqA7GCpg`Ij6IfR!EcUII68}Qj?+(oV_1e-Wi7<=p-sCHoCn*Sr3v`m0b;FP z(?Z9y$>YWDVW;oLnTUbcb2X!5)tCI;?b+4Q_2DCu9N1*5u%W_bUfJNnCx|zTB(3qJ zk`R{tA}FCj0eAi@6@6Zf%wAjd9}JH4StN>@N8fxoPYCtnMqheENkl1HASAOAam`HS zqAEt?%bc2kFJsLYd`epv6y-ht)p17MswSvbaf3ec0+c*zh6-YkPU@<+yR9(oa`vJw zUC$?}x|!3eK`RrUdQwt_$S=M1yZB?MRGU4Z&w-yBuQ9S29HLe=kl6Jcfmq^e48;5~ z-;+6i1~o`v8XFw`vV|4XR{b=su#M|SF%x)tf1ZyKeX1_c47P!>xs$7*kRJ4ITdh}=HV0!uZi9agDsC&A5}|5a43$&=(dUQZMp&yR{kc~1qecGhTB?PU zc_SSqu&QcscqH|PJQnN@4hyX2XqgV1BOjecAp^}>9lnOvp2ebZtL1Bb0GnoZ!`CRv zMiWCBiw#Aair%#>MC#;z;&J0L5%IYyaVx=yNbAP?HtkkO9_-xOVNFpCltmaz4{C%3 zpB166FrbQ}=tD}uq{sEG*iLwzUahQNw!+x~OqE6AQ{AKlqGQ2z(^o;V5iZC9`^jY! zICiqiP0caO8bu^kZW{AISy=>abH(m_r#Oe

@v30%XwEnY&is0VMiRxgrPk-9(_I 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 KYk2?q>;D028Cwki delta 9637 zcmZX41yCJLv-ZKA;O+!>3-0a?!2=;caM!@%5G=sqK(OHM?k>RzPJ#z_=ivN#-&^&4 zH}~JFotdhAdU|(yrgx_MX-$AhHNntOhJ(igfsm0w`=QDS81!&|s+u>pFmUl9%HTYh zH*kl=j9_yNW-uZwCib7UAz2%jKpzMMdiirRf@@&Nz|NAdz#6bt=-mUvjtCm_8k3;c zW#ATAa-LSnje+|WiNhXde7s;|aufG=-0DkKG?u*~BGSeiTI!xxVn3(C;;%2E=Uz8E z+ojvvuwVeL^Iw$`@YnyUL%AN3E`b4os^LH&wtv-8Nx_3hrLcg8#GWW^F1&DPSZ5zL zzr&O}mRCgqRcpD%18h-Ci$mf5FdZ~sNP$0>g|N<*C%Pxr&*X4(F?HeV){g0tA)+J} z`|{cDXx58(zC=rJSn#9831M(MmmFSd{p$|5sJC0+5Ra2h3Fo;oHW9jBqB| zAORJ|ftc0!LUKTmOma;xeGl=j9EMsp21zCzqp?w~w5oB`=WXx8+GD8iF~QY4&wxT&4s11S8bzE{;aN*fR~!KXS^Kv+}#3?5?!q~BajVD0bJ|fiit`E*`Li= z(k#D*sV~kj-Yix0PR1rv3)Hv@A_lL>x^ag45K16Ze_;bCbCXKfC(7h_mSeUNZ~8Z}Z$tZ+Z&fC$NtC#WJ3)STEA~U0s*hth)=fC1pXjdWgM!)eq#Y)~p%x95%`NRW#aZ8~VAFK(q6svz< zSfLg5f%coNV=Q*sTMLgiQ}7HcAH2MPw3TA1)Xr<|@y_J15L5H-Hps-bKqijwQMbcj z4$d*3O}J7V?3QUdSh9r48i@&?C%~a@s(2wArUM;AEr(~XckRJ!v~KOoLeXe67|;hO zoKBOYFY$}l!ipkBx5s~rYk;PvU-MD>YFPDdO&}jtlQ$CP8zUEUCr8aLlaC=DX;Z&B zY#76YY_Vt3o8!2{r~2>#i^TRJmzRAt>%HZUPk{!7J5w8H3eHha+<{{79w4>c&x&2! zXWPPrKSwLdR99p9jpJ@cX7H~SUfbZ~7t~$;Tv<>HW5SH|<^76GeqG8@2P;tbwVBH0 z44n!$G8o?ILF17DD*`hR+cFk0_{%n)w5dR>6nxaCrv!^L&86O`IKThquF-Gz`?i$^ z+*8M)YuIb$J<*?^iZP~gJ>+X9jSxI0dH%NLy$IAM>W?kG5&rl3OhLf`rj+_P@%$;T zC@XKZBCMo8rN;#`-quF^q-<86;bU)O`^ZgR3-Et5wANiDLPu0ppAdy+v@N0Dp{BrI z9QU#l8x-J`ahu{a8KQBsHt~K&bTxte>L#t!AhlG`A>plk{l<;1S>rdy#}Fl}psg$0 zJk7+CpXI!rgXeiYHUcq-0B0zC1(OoFF}x+M`>~Sw*x=C{i3TjrCYer?XocSsZ5Z{! zui|ngFYG@*bQYTqA!pKhJ&v#^ZB2YY3YuC{!xS@N6A*r4Px+?iV zCHW@ST>L4IUPXV++t$7*Op)|w7EeN+?jR-5C_geSrIF#jd9=1O0bJ;wAyc_U!od^1 zT7Tib?S%W$`&M;bWmN^r2)_w_@}up(->Vco?#+X6hn1&CuP`y4?rLXk&*?!Dr5+Z5 zz8hrgp`{C{qXJH(_b*yUhYe(?(d~qS4l?^!XWSyK>O++)pQbOz7|;=0*7g>oGkn;l z?F3wTTB};v1Rq?p=`ZU{x+HC!aj1^ACt-cwfq9nuz&)sHZ>M5tYg}3 zO2nxnxpx$~G%&JKR8tzPkKO&}^oZZvF5=*@b0yvJcz*;YIR&Qu4p3!>@>Ei`;Z&jK zvmNnR?_}_-;@lC(!EeUvP0q4AcU%SDw$&0^tfS-@an3E_I&eU`>Czq~FVXuxF-26|Wr5Fu5c-|X3 z8QT+2b6SVd5W8c&mu$@F0}U{zpzD+)#54P~mkSB<&{&$wD)76&4$1l{@5hCLMq+pi zh`66LR@KF{=NW;pfDpALeP^9%v9j&{+VRnc(X~G6acbCF&#vo(gs2EHTIN-H$HT!l zqpD09x39trAFuw{UV#Q)S$O>gR^dHDH*&39h+B(c6W7+NHBNicibDBE-sHKP#xnTZ z0|r6gpMxjgO$1sWnu5~2_CK&-DRiN3&swcnDT$>jN{`TIKRmLP!crFXl zOV}RGhuT+_K3Lg!jYHTpd*P?<;$-mo_pa5*K?0=qvXbj9q1y)TT$@DZO8#;9(H=GA z{Gt~$#a~353M6~IhKN0xUQM-5Zhu2Rz3V7klRd?r&@Fc@sjbyw??Igva+)hr2eOV| zL^2;ag++lFb&BuM&Qx;IjN{`8OwZqWNOe_TG%IM{p;p!Og>N8wa1EBUVYL8EZGv{FM(-ZekenQW(w0sHlWwUeo>}ub} zFNcF_(MhR2LINYpIUV}aN|%;K@MKgcJ>D%9EQSCTL97u9CZ8%`=$c+jwpjk06A?;c z7XATUA-D<+m?yAicL1)q-pyk=5HWKy%12@^*RqnX7NfmTGl*`QA}UxK zUBpTDWd_amjh|To+FcQ#=7Mm4*A5}s(~d#zZHDTcgj`Gh?0Y!*_D!CZ-@XOvZy9~D zD{}$v?8hWsv=}oks)#`RH92~a*Yb}M!kJ2?k14bkW3eEfIf7#wyIMNRuQY8`bnR4H7f%W|5gs8FERdE$o zJ1&US#iGA&-hR*A>X#bf{_6d*42k_KkHaL?hDX{HJA|; zrdhuNf9@uE)rTBOn8+Hh#WeE}W+W4xvFRbX4Vy{G)R8ogV9SvQRmL;RzAI2K<;d}? zxhT0Yz`puIEZr&f><5N+aq7zIv-7-tnGjHwdIaNoIC4k5kbMPM#xg(ayQw{&hR>Dp zGxe`g{@1y{{c$eQ-16k$Ng+YNwpW8F+^ffLC__r?_$?ErnnRPRWXyR{IPPaTEbK=P zr5J+N`Y6r*`GTGjxw0z@-_8tyYl1ZIaHSmgM+%Bn=#zIc1|m`N=lnjx>VS}E(V9Zb zAK`OkhAiy8evee~5eTb9-%)*RwGQpdHdi7Tx}A^MNjVKQFjR1ts?>IYfy{$je>wVw zNn24IeV?>Fm3g&ESUZ)Nf|Rgh3iPW@*!DL}B6#)CSaQgyreH{|N-f@k7TL6=!Hz46 zretnmDGswUe}SFsm>$`C%%`8~YtJ<(H*SK=%qX9kis_O+uspvqnQ=HOM)y7JI?E4d zUZpr4Hp*cPG#AR7sKR?O<>j|D9PlJG;AruQe1w|lE&jMs;*HiONu(+1 zPQzpC(&Z>}Xkf)hOE6CqY)yKT@0I{TEyv@g!i6GKFnamr&`-M=r^eRy)D9H7oQw-m zjtDploaiiHT|+VDzwWJx4#~ zLRYQKz`P^uQ_Xz0-+bR?gXX_5_Qx+hG+S-djP{HnfPsbva|!~)aw zSVWcNHDxfLtaxm79xTxn_d@rYpVTACOP zt0pG+fpS9h%(0NSt|Y6^6L%qfmlYpQ_X?Vx=kA_oE@Sb(PI9s31eBD{UV3_&WmS4& zsTt_GoA(O=14*b^J zJ^EHvD7;L`&IP%-9Jo1w9?K)G4n|MZWpy+#jJ1!kK$pq2ct2OEH-+Y#I!8Jhe8ope zKqVq{xQ)XyaGd(Vr!kMh-EAN1hajSaXfbPW`>0AUOn@K^v|IC5zdNAQ_^=Y6TF|J* zob?Gc-o&Lgo4s3NG3bq4feJm^YTCOU@~E;O?o9PxVfhqxm|c~ITGDheNic{N-Bb~I zWI%vFUXOy)7MF?$40aFcPSE(fv+`OCney|=z}egE@O;~=MOVdTL)t{8^S2W0nLG|H zj9cjl_QK`oKsSar?rMA$S&S}R=-T_KvIU_j&fC3t%XllR(A14-VwohGL`S=ezD(S7jr@OXQ42lx3C0Q1D_!+qM~;>i)>P#UpC#E>W(tWTS6tV% zKBE!TYT_p)IKm0G*a}3PoARo{(bCkz(RXw(_B&0)T5A=AIdldlzDoRXvy{iN5G;g< zGqR-}(L2-3YQnMPE6L!tIKR)PZTA|RZ#F0;^opxdxnBgm*Cx`|ZQz##x|1L#ap>@* z%GLEYE#RPHl8!EQrueRBZK+%1icjmW(|j}~3RaN$>&-P@ zIms;?F4V^drQ0O(W!|uljSlu5p_}CWmjbkE|s{0r|O6bJ|}jW`-ZT@Nkc zY>Lr2Iu-H=(P!Xne%iCz6Pmcz*;E*MahNTP2%u|dyL%wdY{_qOmf%M3(o-HJ=GSAv@ z4=C@rn-+e|8;vEI=rqkY7UZH;+ma6E*eSW}yHwy}XB)UatOad6v5rVb=6-kCGjV{| zZhzWMUhi`2p|j_FV`Sj^!v4wrcJ<+tlSAbo~-{O3SB zsY4$_au}gp@5laVB5s=Jmh($Ui~xq9UlRYPtOghE#`iEq!nfzqDQoJ!0arJO>5==b z<@fvt3aY=8q=K^ho}c0W>qY;BrVNuUxGFA@K%jW4|M8;w|M8;R2FL1n@z?BFoXyr21CG^Rh6NsGjJE0W8`@!DLs$4ULP2G?B{kpPiH-Jwz_r+iI;eIb$gB!c~Haz0nn55 z@zh@jEP$(v-$pxNU8=Q;e4=`%4UR$A3kjQhxAS<@Qt<1LX~L(V%kz@wXZyGocx!{dQT(Dv>YQlxg4gr?cDFWjzXlJfb z2$OsK-zAG*`cy6)xuRCsA(rydfsG5j??Y3aZ5OjyH75=Xj}Nk*moe0+36uhj@VNTu z?$_IUC!E8+d0cMn@4KI!89PIPqV=6p@t5YC^;B`cSM?C<>^$FPU8r|mi;O-!cjX5> zRH8?XCd4Ufl8;$G3Z!b*cwKF}tKD(0<8Y@UsgPuxt&&7lt+e*pA&Ye83DS9u3G%e- zXC1;hj1W0WXrRVIA8i_7a#asoeXhdN zAV1l5|BW}Ll+&WKl$(TBpmC%`$3g;PP25Is=JTao?~9{|IsEb4C=*#qt#8>H_B~ra za0}p%7-6R33;Qvx>0Q_iH9HGr>IQ8D=yMiT@pT)|g}5Vf`eID4!tEpQ@!s%6krUET zkpIB6MOsXX=K4Z&2fR%Jwp7|Py$lIcUF3Uxlfxl>d(nCFp@+dE*}MkFHcq3}rL(Jp zWaS-f)(4fN(pm6$XaQkqUe)KH0F87k4=r+BMlQ-AQt)G0C7v z=t)K9*%5c@Q?Zqm$M)QMRf1LK2D#vvi(Qy2($5YI3Ou+PU0=QfevPDcd1T^x5c=Lm zzQ#A)%#KmBboHd5o%V=Kl(t#Sq3h`xVipcFK4z^6`>K77aeg*Eeqws2R27lySJ-sw zyvFrSMJJ8oV9{gOsB^FDm&T~a=<+#SYhK;R47e4S%Ksm zq?dfppjGOZVpl;|g-o2uah1HOj=>bSFt4r{E<<~idEL!>m-pI4jk-hlHF0z@Wbjhm z65S3NZcbBJ-`3MTaq>5#G)a-olt{V^c&1}n!^KMqNR*k$JpRbclJ8!v?_T~I zHF39_&qHDLW^TrjZU2>pT4!$9e|&OTTpqEyYTIN=pu2A zd`%?TVu$}_)A|71s>m%kC9=VZZDGC>qtNLto$%2$H6ffF&Gt6pT40uC3$IBx(wI?0 zqpMU@?A7!m#G^$b4pG83WKnq-gAS2Yi5iB!m(hd)$SNt#=f3Abd}l-yOv$ybVHlP* zv<07rc|)ddu3P_0N71~eR~b0265?&JG>)u5HV+{(peni9%7HDra_LMz-41ek z>1#Q8N%~F&YpD2vQYa|Q_SgzDdW*(Jkj!sP*W&yoBlQ_=pSrn;VyqILNBen1>v}=| z`2rsSs2P;IGkY42Ugg}e4yH6iYyDcspmMMXu{Vv@59 zTm<1JEfCHBVfBSv?3YIT021*tu0uP)dkH#30FtyWRbOE2da0ZjV!LSG>`S-jCgexP z9*IFNb^8?dvQ@FM!h2vJGZlLKd%>2t%GQ!Ak;oc2o%%p$ z?G^jv!;II{T^Z};ptBD5QfFpHovb`MSS^x&IPgkB!?THygD)e)Kur>2rEAd>!p)`x zc$JKPoW5}(6QV;J==5NH`{9@Ar+!ySXMc<&Rdxjoy$T1>sw93q2L0oG@lGt(wH=Qy z6qGi1xc%D$BRe>Ls#xgRr02Vo;DQU*LxHzau@2FT@^Drk2Y3C;neHRbW~6Sfa^BW$ zlz+Y*t&R?F$I%{Fol$ypBNHi#e1Ayx1aQyf&rdZWYE|b>VxUOy=X}IhyJHWgmqN&U zMYVTipaa#xf%b&kPS~HpK)x_CV`7oEsY0ycUSJ?`?^4S>tYhYnhNC4{&d%`5yzF9M z4etn_*=@85_!MYU?0Gh`oZV1GB`wC0P{Pp}bNlAuq|*!@wUb5;mo528()$gX&<~bB zLv(@*EgOkum4N>hDtq)-HspcWeGW$kfu@xH*(!ij70`fV<70JPMWPqS-!Gh>&9ZxP zq31Gj(Z0iUgKavvVy4Np3I&eo#{_X$i5GejOxx|uup`PcpIR0zuBww(_VeO!C6f4+Pue{({MtkKcVC#mtdE9*|Blh~aCQx$YC08U~(NSkSzj zgQ~>Y$trrt_^fe!D!V?>L*_QH9}N}AK`dAqu|(MZIO^d#IGcN@bc5&6i)f$6-)!%t z+MHcQyPBhQeu{R;_hlPf0V_CBcsXu;lq6^B=|l%m`IvGKjX8ZJV1Z04lc;zmnw-X*i{Ex+fNXtkUQss9C4|1f zZhD8{7CYszv6N%5v-%d{dzPld-iAzIg7M_j<<}bRw>Qq_A33SCq;uK&+KFKM^H@%R zvXioUrY+odk^Ac%46AoP{K9TLP1~{1p?ChK)fAGy2VgK2PUCQTeh?iT$!KMZ2g-et z7R#2KHO4YRFAk@XG5tC)tQ%zl$z@rr5bFuwmo$x&5K0C)d89GJzG-o;msw;##kX49 zyu!3OsI@>%Q4ZIr&Abv}OjnEB1YgVmCbnYevvcL)$n=x)$boy^DRtSpt-Idu;f|7~ zwY5AX)Z=kmB8IA>;=VQzJq%O_CW%w|Y%s#$a`wH!VOBmMl|?ScfY%E^Fh8HBAqAD` z_)l(Rd5aCM7i>y3hH`4QBzYDKW!(`qVD5|+M+zkJ)gE8C&*|y1ycEd1bM$PRbN zEj^f>F(@H~ml07;D)Iw@!uSJZ*rp*Ad^i9h4u`*1iTdUwBMxJg)^n%=35%jJGD9Mv zGbzX$nXkn2$oAU<^br>3)>YYd11pa4Gjq75x4p|4=O+9uXOx-|qd0_D`nY=5+@-Q% z>eZBNxNxgc9}E$Ue9m=)JS&o?=tVyA%_p`FQxh1BH%{0FjIGkiDYmJPSdo$H;Gxwer;d!W`^s*Syi}P78zrNw~c@8eM z;=;&x1{aUnr$H%lPfD^|yf7Ltb0@IYGp;(jU&9^&-XEPG4c=!G!o`-Z+$i{-Sd*Od zK&GmF;tHRK3uV={0}?&MId>WL-{Zi0-lhrd7FcD*>W=dZ4hbA;C8Z6gw-fjZrAT$@ z0SDRb6+y}og}B1ep#G7-xL=$d%uy_UqlfssqGqF)LIjFv&j8UlO?t zx}A^!dRAh)jiO3>+I4Py4?=yRnF!LE0_M+;^-~h&nAHbR<=XVS5DeX!5$M}eAzGy| zu?$*{&K@^Efd;eN<`4M{eo*B#IGSij()zi?U93Bz_!N;6_pJx!gZD;$!Q9LUI+hTTcmEyWBA2mf!=Ns9bmnZGDE|B(TK@`F16 z0n&gcq=^3o{>9_?3s{TzFYpr*2J8R+rhne(FT%iILfOdw3ZZ`c z0X~vOr~3cWqJIGm(fUjNmR zF3vw-7%i}*90Aqep{V~0EhGH5-&1))s=qg){};GU`7bb40T&Y&gbP~wlO8B${738m E16c|8>i_@% diff --git a/src/main/java/fybug/nulll/pdconcurrent/SyLock.java b/src/main/java/fybug/nulll/pdconcurrent/SyLock.java index 1134550..32216c4 100644 --- a/src/main/java/fybug/nulll/pdconcurrent/SyLock.java +++ b/src/main/java/fybug/nulll/pdconcurrent/SyLock.java @@ -1,528 +1,28 @@ package fybug.nulll.pdconcurrent; -import java.util.function.Consumer; -import java.util.function.Function; - import fybug.nulll.pdconcurrent.e.LockType; -import fybug.nulll.pdconcurrent.fun.tryRunnable; -import fybug.nulll.pdconcurrent.fun.trySupplier; -import jakarta.annotation.Nullable; +import fybug.nulll.pdconcurrent.i.ReadWriteLock; +import fybug.nulll.pdconcurrent.i.TryReadWriteLock; +import fybug.nulll.pdconcurrent.lock.ObjLock; +import fybug.nulll.pdconcurrent.lock.RWLock; +import fybug.nulll.pdconcurrent.lock.ReLock; import jakarta.validation.constraints.NotNull; /** *

并发管理.

* 通过传入回调的方式隐藏内部的并发管理方法,并支持复用内部的try块,通过传入的回调插入到catch,finally块中执行
- * {@code **lock()} 方法用于根据传入的{@link LockType}申请不同的锁类型进行执行
- * {@code **read()} 方法用于申请使用读锁,{@code **write()} 用于申请使用写锁,只有在使用读写锁实现 {@link RWLock} 才有区别。其余实现两个之间无区别
- * {@code try**()} 类型的方法为可抛出异常的方法,可在传入的接口中抛出异常 + * {@code lock()}方法用于根据传入的{@link LockType}申请不同的锁类型进行执行
+ * {@code read()}方法用于使用读锁执行,{@code write()}用于使用写锁执行,只有在使用读写锁实现{@link RWLock}才有区别。其余实现两个之间无区别
+ * {@code trylock()}类型的方法为尝试获取锁的实现,这意味着并不是一定能获取到锁,但也意味着不需要等待
+ * 上述方法均有可抛出异常的变种 *

* 使用 {@code new**Lock()} 的方法获取不同并发管理的实例
* * @author fybug - * @version 0.1.1 + * @version 0.1.2 * @since PDConcurrent 0.0.1 */ public -interface SyLock { - /** - * 使用锁执行指定回调 - *

- * 可通过传入{@link LockType}指定锁的类型,运行时自带try-catch-finally块,通过三个回调参数插入不同的块中执行
- * 所有回调均在并发域内执行 - * - * @param lockType 锁类型 - * @param run 带返回的回调 - * @param catchby 进入catch块后的回调,传入当前异常 - * @param finaby 进入finally块后的回调,传入前两个回调的返回值 - * @param 要返回的数据类型 - * - * @return 回调返回的内容 - * - * @implSpec 如果有传入 {@code finaby} 回调则返回值由{@code finaby}主导,传入{@code finaby}的值根据是否发生异常传入{@code run}的返回值或{@code catchby}的返回值
- * 任意一个回调为空时直接穿透,使用上一个正确执行的值进行传递或者返回,传递值应默认为{@code null}用于应对{@code catchby}和{@code finaby}都为空但是发生了异常的情况 - * @see trySupplier - * @see Function - * @see LockType - * @since 0.1.0 - */ - R lock(@NotNull LockType lockType, @NotNull trySupplier run, @Nullable Function catchby, - @Nullable Function finaby); - - /** - * 使用锁执行指定回调 - *

- * 可通过传入{@link LockType}指定锁的类型,运行时自带try-catch-finally块,通过三个回调参数插入不同的块中执行
- * 所有回调均在并发域内执行 - * - * @param lockType 锁类型 - * @param run 执行的回调 - * @param catchby 进入catch块后的回调,传入当前异常 - * @param finaby 进入finally块后的回调 - * - * @see tryRunnable - * @see Consumer - * @see Runnable - * @see LockType - * @see #lock(LockType, trySupplier, Function, Function) - * @since 0.1.0 - */ - default - void lock(@NotNull LockType lockType, @NotNull tryRunnable run, @Nullable Consumer catchby, - @Nullable Runnable finaby) - { - lock(lockType, () -> { - run.run(); - return null; - }, catchby == null ? null : e -> { - catchby.accept(e); - return null; - }, finaby == null ? null : _ -> { - finaby.run(); - return null; - }); - } - - /** - * 使用锁执行指定回调 - *

- * 可通过传入{@link LockType}指定锁的类型,运行时自带try-catch-finally块,遇到异常不处理返回{@code null} - * - * @param lockType 锁类型 - * @param run 带返回的回调 - * @param 要返回的数据类型 - * - * @return 回调返回的内容,遇到异常返回{@code null} - * - * @see trySupplier - * @see LockType - * @see #lock(LockType, trySupplier, Function, Function) - * @since 0.1.0 - */ - default - R lock(@NotNull LockType lockType, @NotNull trySupplier run) - { return lock(lockType, run, null, null); } - - /** - * 使用锁执行指定回调 - *

- * 可通过传入{@link LockType}指定锁的类型,运行时自带try-catch-finally块,遇到异常不处理 - * - * @param lockType 锁类型 - * @param run 执行的回调 - * - * @see tryRunnable - * @see LockType - * @see #lock(LockType, tryRunnable, Consumer, Runnable) - * @since 0.1.0 - */ - default - void lock(@NotNull LockType lockType, @NotNull tryRunnable run) - { lock(lockType, run, null, null); } - - /** - * 尝试使用锁执行指定回调 - *

- * 可通过传入{@link LockType}指定锁的类型,运行时自带try-finally块,通过两个回调参数插入不同的块中执行,遇到异常会抛出
- * 所有回调均在并发域内执行 - * - * @param lockType 锁类型 - * @param run 带返回的回调 - * @param finaby 进入finally块后的回调,传入前一个回调的返回值,遇到异常传入{@code null} - * @param 要返回的数据类型 - * - * @return 回调返回的内容,遇到异常不返回 - * - * @throws Exception 异常类型根据实际运行时回调抛出决定 - * @throws Exception 异常类型根据实际运行时回调抛出决定 - * @implSpec 如果有传入 {@code finaby} 回调则返回值由{@code finaby}主导,传入{@code finaby}的值根据是否发生异常传入{@code run}的返回值或{@code null}
- * 任意一个回调为空时直接穿透,使用上一个正确执行的值进行传递或者返回,发生异常会执行{@code finaby}但是不会返回内容 - * @see trySupplier - * @see Function - * @see LockType - * @since 0.1.0 - */ - R trylock(@NotNull LockType lockType, @NotNull trySupplier run, @Nullable Function finaby) throws Exception; - - /** - * 尝试使用锁执行指定回调 - *

- * 可通过传入{@link LockType}指定锁的类型,运行时自带try-finally块,通过两个回调参数插入不同的块中执行,遇到异常会抛出
- * 所有回调均在并发域内执行 - * - * @param lockType 锁类型 - * @param run 执行的回调 - * @param finaby 进入finally块后的回调 - * - * @throws Exception 异常类型根据实际运行时回调抛出决定 - * @see tryRunnable - * @see Runnable - * @see LockType - * @see #trylock(LockType, trySupplier, Function) - * @since 0.1.0 - */ - default - void trylock(@NotNull LockType lockType, @NotNull tryRunnable run, @Nullable Runnable finaby) throws Exception { - trylock(lockType, () -> { - run.run(); - return null; - }, finaby == null ? null : _ -> { - finaby.run(); - return null; - }); - } - - /** - * 尝试使用锁执行指定回调 - *

- * 可通过传入{@link LockType}指定锁的类型,运行时自带try-finally块,遇到异常会抛出 - * - * @param lockType 锁类型 - * @param run 带返回的回调 - * @param 要返回的数据类型 - * - * @return 回调返回的内容,遇到异常不返回 - * - * @throws Exception 异常类型根据实际运行时回调抛出决定 - * @see trySupplier - * @see LockType - * @see #trylock(LockType, trySupplier, Function) - * @since 0.1.0 - */ - default - R trylock(@NotNull LockType lockType, @NotNull trySupplier run) throws Exception - { return trylock(lockType, run, null); } - - /** - * 尝试使用锁执行指定回调 - *

- * 可通过传入{@link LockType}指定锁的类型,运行时自带try-finally块,遇到异常会抛出 - * - * @param lockType 锁类型 - * @param run 执行的回调 - * - * @throws Exception 异常类型根据实际运行时回调抛出决定 - * @see tryRunnable - * @see LockType - * @see #trylock(LockType, tryRunnable, Runnable) - * @since 0.1.0 - */ - default - void trylock(@NotNull LockType lockType, @NotNull tryRunnable run) throws Exception - { trylock(lockType, run, null); } - - /** - * 使用读锁执行指定回调 - *

- * 调用读锁执行,运行时自带try-catch-finally块,遇到异常不处理 - * - * @param run 带返回的回调 - * @param 要返回的数据类型 - * - * @return 回调返回的内容 - * - * @see trySupplier - * @see LockType#READ - * @see #lock(LockType, trySupplier, Function, Function) - * @since 0.1.0 - */ - default - R read(@NotNull trySupplier run) - { return lock(LockType.READ, run, null, null); } - - /** - * 使用读锁执行指定回调 - *

- * 调用读锁执行,运行时自带try-catch-finally块,遇到异常不处理 - * - * @param run 执行的回调 - * - * @see tryRunnable - * @see LockType#READ - * @see #lock(LockType, tryRunnable, Consumer, Runnable) - * @since 0.1.0 - */ - default - void read(@NotNull tryRunnable run) - { lock(LockType.READ, run, null, null); } - - /** - * 使用写锁执行指定回调 - *

- * 调用写锁执行,运行时自带try-catch-finally块,遇到异常不处理 - * - * @param run 带返回的回调 - * @param 要返回的数据类型 - * - * @return 回调返回的内容 - * - * @see trySupplier - * @see LockType#WRITE - * @see #lock(LockType, trySupplier, Function, Function) - * @since 0.1.0 - */ - default - R write(@NotNull trySupplier run) - { return lock(LockType.WRITE, run, null, null); } - - /** - * 使用写锁执行指定回调 - *

- * 调用写锁执行,运行时自带try-catch-finally块,遇到异常不处理 - * - * @param run 执行的回调 - * - * @see tryRunnable - * @see LockType#WRITE - * @see #lock(LockType, tryRunnable, Consumer, Runnable) - * @since 0.1.0 - */ - default - void write(@NotNull tryRunnable run) - { lock(LockType.WRITE, run, null, null); } - - /** - * 使用读锁执行指定回调 - *

- * 调用读锁执行,运行时自带try-catch-finally块,通过三个回调参数插入不同的块中执行
- * 所有回调均在并发域内执行 - * - * @param run 带返回的回调 - * @param catchby 进入catch块后的回调,传入当前异常 - * @param finaby 进入finally块后的回调,传入前两个回调的返回值 - * @param 要返回的数据类型 - * - * @return 回调返回的内容 - * - * @see trySupplier - * @see Function - * @see LockType#READ - * @see #lock(LockType, trySupplier, Function, Function) - * @since 0.1.0 - */ - default - R read(@NotNull trySupplier run, @Nullable Function catchby, @Nullable Function finaby) - { return lock(LockType.READ, run, catchby, finaby); } - - /** - * 使用读锁执行指定回调 - *

- * 调用读锁执行,运行时自带try-catch-finally块,通过三个回调参数插入不同的块中执行
- * 所有回调均在并发域内执行 - * - * @param run 执行的回调 - * @param catchby 进入catch块后的回调,传入当前异常 - * @param finaby 进入finally块后的回调 - * - * @see tryRunnable - * @see Consumer - * @see Runnable - * @see LockType#READ - * @see #lock(LockType, tryRunnable, Consumer, Runnable) - * @since 0.1.0 - */ - default - void read(@NotNull tryRunnable run, @Nullable Consumer catchby, @Nullable Runnable finaby) - { lock(LockType.READ, run, catchby, finaby); } - - /** - * 使用写锁执行指定回调 - *

- * 调用写锁执行,运行时自带try-catch-finally块,通过三个回调参数插入不同的块中执行
- * 所有回调均在并发域内执行 - * - * @param run 带返回的回调 - * @param catchby 进入catch块后的回调,传入当前异常 - * @param finaby 进入finally块后的回调,传入前两个回调的返回值 - * @param 要返回的数据类型 - * - * @return 回调返回的内容 - * - * @see trySupplier - * @see Function - * @see LockType#WRITE - * @see #lock(LockType, trySupplier, Function, Function) - * @since 0.1.0 - */ - default - R write(@NotNull trySupplier run, @Nullable Function catchby, @Nullable Function finaby) - { return lock(LockType.WRITE, run, catchby, finaby); } - - /** - * 使用写锁执行指定回调 - *

- * 调用写锁执行,运行时自带try-catch-finally块,通过三个回调参数插入不同的块中执行
- * 所有回调均在并发域内执行 - * - * @param run 执行的回调 - * @param catchby 进入catch块后的回调,传入当前异常 - * @param finaby 进入finally块后的回调 - * - * @see tryRunnable - * @see Consumer - * @see Runnable - * @see LockType#WRITE - * @see #lock(LockType, tryRunnable, Consumer, Runnable) - * @since 0.1.0 - */ - default - void write(@NotNull tryRunnable run, @Nullable Consumer catchby, @Nullable Runnable finaby) - { lock(LockType.WRITE, run, catchby, finaby); } - - /** - * 尝试使用读锁执行指定回调 - *

- * 调用读锁执行,运行时自带try-finally块,遇到异常会抛出 - * - * @param run 带返回的回调 - * @param 要返回的数据类型 - * - * @return 回调返回的内容,遇到异常不返回 - * - * @throws Exception 异常类型根据实际运行时回调抛出决定 - * @see trySupplier - * @see LockType#READ - * @see #trylock(LockType, trySupplier, Function) - * @since 0.1.0 - */ - default - R tryread(@NotNull trySupplier run) throws Exception - { return trylock(LockType.READ, run, null); } - - /** - * 尝试使用读锁执行指定回调 - *

- * 调用读锁执行,运行时自带try-finally块,遇到异常会抛出 - * - * @param run 执行的回调 - * - * @throws Exception 异常类型根据实际运行时回调抛出决定 - * @see tryRunnable - * @see LockType#READ - * @see #trylock(LockType, tryRunnable, Runnable) - * @since 0.1.0 - */ - default - void tryread(@NotNull tryRunnable run) throws Exception - { trylock(LockType.READ, run, null); } - - /** - * 尝试使用写锁执行指定回调 - *

- * 调用写锁执行,运行时自带try-finally块,遇到异常会抛出 - * - * @param run 带返回的回调 - * @param 要返回的数据类型 - * - * @return 回调返回的内容,遇到异常不返回 - * - * @throws Exception 异常类型根据实际运行时回调抛出决定 - * @see trySupplier - * @see LockType#WRITE - * @see #trylock(LockType, trySupplier, Function) - * @since 0.1.0 - */ - default - R trywrite(@NotNull trySupplier run) throws Exception - { return trylock(LockType.WRITE, run, null); } - - /** - * 尝试使用写锁执行指定回调 - *

- * 调用写锁执行,运行时自带try-finally块,遇到异常会抛出 - * - * @param run 执行的回调 - * - * @throws Exception 异常类型根据实际运行时回调抛出决定 - * @see tryRunnable - * @see LockType#WRITE - * @see #trylock(LockType, tryRunnable, Runnable) - * @since 0.1.0 - */ - default - void trywrite(@NotNull tryRunnable run) throws Exception - { trylock(LockType.WRITE, run, null); } - - /** - * 尝试使用读锁执行指定回调 - *

- * 调用读锁执行,运行时自带try-finally块,通过两个回调参数插入不同的块中执行,遇到异常会抛出
- * 所有回调均在并发域内执行 - * - * @param run 带返回的回调 - * @param finaby 进入finally块后的回调,传入前一个回调的返回值,遇到异常传入{@code null} - * @param 要返回的数据类型 - * - * @return 回调返回的内容,遇到异常不返回 - * - * @throws Exception 异常类型根据实际运行时回调抛出决定 - * @see trySupplier - * @see LockType#READ - * @see #trylock(LockType, trySupplier, Function) - * @since 0.1.0 - */ - default - R tryread(@NotNull trySupplier run, @Nullable Function finaby) throws Exception - { return trylock(LockType.READ, run, finaby); } - - /** - * 尝试使用读锁执行指定回调 - *

- * 调用读锁执行,运行时自带try-finally块,通过两个回调参数插入不同的块中执行,遇到异常会抛出
- * 所有回调均在并发域内执行 - * - * @param run 执行的回调 - * @param finaby 进入finally块后的回调 - * - * @throws Exception 异常类型根据实际运行时回调抛出决定 - * @see trySupplier - * @see LockType#READ - * @see #trylock(LockType, tryRunnable, Runnable) - * @since 0.1.1 - */ - default - void tryread(@NotNull tryRunnable run, @Nullable Runnable finaby) throws Exception - { trylock(LockType.READ, run, finaby); } - - /** - * 尝试使用写锁执行指定回调 - *

- * 调用写锁执行,运行时自带try-finally块,通过两个回调参数插入不同的块中执行,遇到异常会抛出
- * 所有回调均在并发域内执行 - * - * @param run 带返回的回调 - * @param finaby 进入finally块后的回调,传入前一个回调的返回值,遇到异常传入{@code null} - * @param 要返回的数据类型 - * - * @return 回调返回的内容,遇到异常不返回 - * - * @throws Exception 异常类型根据实际运行时回调抛出决定 - * @see trySupplier - * @see LockType#WRITE - * @see #trylock(LockType, trySupplier, Function) - * @since 0.1.1 - */ - default - R trywrite(@NotNull trySupplier run, @Nullable Function finaby) throws Exception - { return trylock(LockType.WRITE, run, finaby); } - - /** - * 尝试使用写锁执行指定回调 - *

- * 调用写锁执行,运行时自带try-finally块,通过两个回调参数插入不同的块中执行,遇到异常会抛出
- * 所有回调均在并发域内执行 - * - * @param run 执行的回调 - * @param finaby 进入finally块后的回调 - * - * @throws Exception 异常类型根据实际运行时回调抛出决定 - * @see trySupplier - * @see LockType#WRITE - * @see #trylock(LockType, tryRunnable, Runnable) - * @since 0.1.1 - */ - default - void trywrite(@NotNull tryRunnable run, @Nullable Runnable finaby) throws Exception - { trylock(LockType.WRITE, run, finaby); } - +interface SyLock extends ReadWriteLock, TryReadWriteLock { /** * 获取传统并发实现 * @@ -530,6 +30,7 @@ interface SyLock { * * @see ObjLock */ + @SuppressWarnings("unused") @NotNull static ObjLock newObjLock() { return new ObjLock(); } @@ -541,6 +42,7 @@ interface SyLock { * * @see ReLock */ + @SuppressWarnings("unused") @NotNull static ReLock newReLock() { return new ReLock(); } @@ -552,6 +54,7 @@ interface SyLock { * * @see RWLock */ + @SuppressWarnings("unused") @NotNull static RWLock newRWLock() { return new RWLock(); } diff --git a/src/main/java/fybug/nulll/pdconcurrent/e/LockType.java b/src/main/java/fybug/nulll/pdconcurrent/e/LockType.java index 0562106..0df827d 100644 --- a/src/main/java/fybug/nulll/pdconcurrent/e/LockType.java +++ b/src/main/java/fybug/nulll/pdconcurrent/e/LockType.java @@ -5,7 +5,7 @@ package fybug.nulll.pdconcurrent.e; * * @author fybug * @version 0.0.1 - * @since PDConcurrent 0.1.0 + * @since e 0.0.1 */ public enum LockType { @@ -13,6 +13,10 @@ enum LockType { READ, /** 写锁 */ WRITE, - /** 不上锁 */ + /** + * 不上锁 + *

+ * 该方式要求这次锁行为不会被记录与执行,故解锁时本次行为会被跳过转而解锁上一次的锁 + */ NOLOCK } diff --git a/src/main/java/fybug/nulll/pdconcurrent/fun/tryConsumer.java b/src/main/java/fybug/nulll/pdconcurrent/fun/tryConsumer.java index b1a3114..c9dde4d 100644 --- a/src/main/java/fybug/nulll/pdconcurrent/fun/tryConsumer.java +++ b/src/main/java/fybug/nulll/pdconcurrent/fun/tryConsumer.java @@ -12,6 +12,8 @@ import jakarta.validation.constraints.NotNull; * @see Consumer * @since fun 0.0.4 */ +@SuppressWarnings("unused") +@FunctionalInterface public interface tryConsumer { /** @see Consumer#accept(Object) */ diff --git a/src/main/java/fybug/nulll/pdconcurrent/fun/tryFunction.java b/src/main/java/fybug/nulll/pdconcurrent/fun/tryFunction.java index d3fa122..af64f16 100644 --- a/src/main/java/fybug/nulll/pdconcurrent/fun/tryFunction.java +++ b/src/main/java/fybug/nulll/pdconcurrent/fun/tryFunction.java @@ -13,6 +13,8 @@ import jakarta.validation.constraints.NotNull; * @see Function * @since fun 0.0.4 */ +@SuppressWarnings("unused") +@FunctionalInterface public interface tryFunction { /** @see Function#apply(Object) */ @@ -33,6 +35,7 @@ interface tryFunction { tryFunction andThen(@Nullable tryFunction after) { if ( after != null ) return t -> after.apply(apply(t)); + //noinspection unchecked return (tryFunction) this; } } diff --git a/src/main/java/fybug/nulll/pdconcurrent/fun/tryRunnable.java b/src/main/java/fybug/nulll/pdconcurrent/fun/tryRunnable.java index 99be436..6733067 100644 --- a/src/main/java/fybug/nulll/pdconcurrent/fun/tryRunnable.java +++ b/src/main/java/fybug/nulll/pdconcurrent/fun/tryRunnable.java @@ -8,6 +8,7 @@ import jakarta.validation.constraints.NotNull; * @see Runnable * @since fun 0.0.4 */ +@SuppressWarnings("unused") @FunctionalInterface public interface tryRunnable { diff --git a/src/main/java/fybug/nulll/pdconcurrent/fun/trySupplier.java b/src/main/java/fybug/nulll/pdconcurrent/fun/trySupplier.java index 5acbc79..d59a835 100644 --- a/src/main/java/fybug/nulll/pdconcurrent/fun/trySupplier.java +++ b/src/main/java/fybug/nulll/pdconcurrent/fun/trySupplier.java @@ -12,6 +12,7 @@ import jakarta.validation.constraints.NotNull; * @see Supplier * @since fun 0.0.4 */ +@SuppressWarnings("unused") @FunctionalInterface public interface trySupplier { @@ -19,6 +20,7 @@ interface trySupplier { R get() throws Exception; /** @since 0.0.2 */ + @SuppressWarnings("unused") @NotNull default tryRunnable andThen(@Nullable tryConsumer after) { @@ -28,11 +30,13 @@ interface trySupplier { } /** @since 0.0.2 */ + @SuppressWarnings("unused") @NotNull default trySupplier andThen(@Nullable tryFunction after) { if ( after != null ) return () -> after.apply(get()); + //noinspection unchecked return (trySupplier) this; } } diff --git a/src/main/java/fybug/nulll/pdconcurrent/i/AbstractSyLock.java b/src/main/java/fybug/nulll/pdconcurrent/i/AbstractSyLock.java new file mode 100644 index 0000000..f4dba53 --- /dev/null +++ b/src/main/java/fybug/nulll/pdconcurrent/i/AbstractSyLock.java @@ -0,0 +1,216 @@ +package fybug.nulll.pdconcurrent.i; +import java.util.function.Function; + +import fybug.nulll.pdconcurrent.SyLock; +import fybug.nulll.pdconcurrent.e.LockType; +import fybug.nulll.pdconcurrent.fun.tryFunction; +import fybug.nulll.pdconcurrent.fun.trySupplier; +import jakarta.annotation.Nullable; +import jakarta.validation.constraints.NotNull; + +/** + *

读写锁管理基本框架.

+ * + * @author fybug + * @version 0.0.1 + * @since i 0.0.1 + */ +@SuppressWarnings("unused") +public abstract +class AbstractSyLock implements SyLock { + /** + * {@inheritDoc} + * + * @param lockType {@inheritDoc} + * @param run {@inheritDoc} + * @param catchby {@inheritDoc} + * @param finaby {@inheritDoc} + * @param {@inheritDoc} + * + * @return {@inheritDoc} + * + * @implNote 使用 {@link #lock(LockType)} 与 {@link #unlock()} 方法实现上锁与解锁 + */ + @Override + public + R lock(@NotNull LockType lockType, @NotNull trySupplier run, @Nullable Function catchby, + @Nullable Function finaby) + { + R o = null; + // 防止finally内的回调抛异常 + try { + try { + // 上锁 + lock(lockType); + // 主要内容 + o = run.get(); + } catch ( Exception e ) { + // 异常处理 + if ( catchby != null ) + o = catchby.apply(e); + } finally { + // 收尾 + if ( finaby != null ) + o = finaby.apply(o); + } + } finally { + unlock(); + } + return o; + } + + /** + * {@inheritDoc} + * + * @param lockType {@inheritDoc} + * @param run {@inheritDoc} + * @param finaby {@inheritDoc} + * @param {@inheritDoc} + * + * @return {@inheritDoc} + * + * @implNote 使用 {@link #lock(LockType)} 与 {@link #unlock()} 方法实现上锁与解锁 + */ + @Override + public + R lock(@NotNull LockType lockType, @NotNull trySupplier run, @Nullable Function finaby) throws Exception { + R o = null; + // 防止finally内的回调抛异常 + try { + try { + // 上锁 + lock(lockType); + // 主要内容 + o = run.get(); + } finally { + // 收尾 + if ( finaby != null ) + o = finaby.apply(o); + } + } finally { + unlock(); + } + return o; + } + + /** + * {@inheritDoc} + * + * @param lockType {@inheritDoc} + * @param run {@inheritDoc} + * @param catchby {@inheritDoc} + * @param finaby {@inheritDoc} + * @param {@inheritDoc} + * + * @return {@inheritDoc} + * + * @implNote 使用 {@link #trylock(LockType)} 与 {@link #unlock()} 方法实现上锁与解锁 + */ + @Override + public + R trylock(@NotNull LockType lockType, @NotNull tryFunction run, @Nullable Function catchby, + @Nullable Function finaby) + { + R o = null; + // 防止finally内的回调抛异常 + try { + try { + // 上锁 + o = run.apply(trylock(lockType)); + } catch ( Exception e ) { + // 异常处理 + if ( catchby != null ) + o = catchby.apply(e); + } finally { + // 收尾 + if ( finaby != null ) + o = finaby.apply(o); + } + } finally { + unlock(); + } + return o; + } + + /** + * {@inheritDoc} + * + * @param lockType {@inheritDoc} + * @param run {@inheritDoc} + * @param finaby {@inheritDoc} + * @param {@inheritDoc} + * + * @return {@inheritDoc} + * + * @throws Exception {@inheritDoc} + * @implNote 使用 {@link #trylock(LockType)} 与 {@link #unlock()} 方法实现上锁与解锁 + */ + @Override + public + R trylock(@NotNull LockType lockType, @NotNull tryFunction run, @Nullable Function finaby) + throws Exception + { + R o = null; + // 防止finally内的回调抛异常 + try { + try { + // 上锁 + o = run.apply(trylock(lockType)); + } finally { + // 收尾 + if ( finaby != null ) + o = finaby.apply(o); + } + } finally { + unlock(); + } + return o; + } + + /** + * 上锁函数 + * + * @param lockType 锁类型 + * + * @throws Exception 可能抛出的异常 + * @implSpec 在此处实现上锁功能 + */ + protected abstract + void lock(@NotNull LockType lockType) throws Exception; + + /** + * 尝试上锁函数 + * + * @param lockType 锁类型 + * + * @return 是否成功上锁 + * + * @implSpec 在此处实现尝试上锁功能 + */ + protected abstract + boolean trylock(@NotNull LockType lockType); + + /** + * 解锁函数 + * + * @implSpec 在此处实现解锁功能,解锁的类型按照最后上锁的类型处理 + */ + public abstract + void unlock(); + + /** + * 检查锁是否被占用 + * + * @return 是否被占用 + */ + public abstract + boolean isLocked(); + + /** + * 检查当前线程是否持有锁 + * + * @return 当前线程是否持有锁 + */ + public abstract + boolean isLockedCurrentThread(); +} diff --git a/src/main/java/fybug/nulll/pdconcurrent/i/Lock.java b/src/main/java/fybug/nulll/pdconcurrent/i/Lock.java new file mode 100644 index 0000000..7c5a94f --- /dev/null +++ b/src/main/java/fybug/nulll/pdconcurrent/i/Lock.java @@ -0,0 +1,140 @@ +package fybug.nulll.pdconcurrent.i; +import java.util.function.Consumer; +import java.util.function.Function; + +import fybug.nulll.pdconcurrent.e.LockType; +import fybug.nulll.pdconcurrent.fun.tryRunnable; +import fybug.nulll.pdconcurrent.fun.trySupplier; +import jakarta.annotation.Nullable; +import jakarta.validation.constraints.NotNull; + +/** + *

基础锁管理.

+ * 通过传入回调的方式隐藏内部的并发管理方法,并支持复用内部的try块,通过传入的回调插入到catch,finally块中执行
+ * {@code lock()}方法用于根据传入的{@link LockType}申请不同的锁类型进行执行
+ * 有可抛出异常的方法变体,可在传入的接口中抛出异常 + * + * @author fybug + * @version 0.0.1 + * @see LockType + * @since i 0.0.1 + */ +interface Lock { + /** + * 使用锁执行指定回调 + *

+ * 可通过传入{@link LockType}指定锁的类型,运行时自带try-catch-finally块,通过三个回调参数插入不同的块中执行
+ * 所有回调均在并发域内执行 + * + * @param lockType 锁类型 + * @param run 带返回的回调 + * @param catchby 进入catch块后的回调,传入当前异常 + * @param finaby 进入finally块后的回调,传入前两个回调的返回值 + * @param 要返回的数据类型 + * + * @return 回调返回的内容 + * + * @implSpec 如果有传入 {@code finaby} 回调则返回值由{@code finaby}主导,传入{@code finaby}的值根据是否发生异常传入{@code run}的返回值或{@code catchby}的返回值
+ * 任意一个回调为空时直接穿透,使用上一个正确执行的值进行传递或者返回,传递值应默认为{@code null}用于应对{@code catchby}和{@code finaby}都为空但是发生了异常的情况 + */ + R lock(@NotNull LockType lockType, @NotNull trySupplier run, @Nullable Function catchby, + @Nullable Function finaby); + + /** + * 使用锁执行指定回调 + *

+ * {@link #lock(LockType, trySupplier, Function, Function)}的无返回变体 + * + * @param lockType 锁类型 + * @param run 执行的回调 + * @param catchby 进入catch块后的回调,传入当前异常 + * @param finaby 进入finally块后的回调 + */ + default + void lock(@NotNull LockType lockType, @NotNull tryRunnable run, @Nullable Consumer catchby, + @Nullable Runnable finaby) + { + lock(lockType, () -> { + run.run(); + return null; + }, catchby == null ? null : e -> { + catchby.accept(e); + return null; + }, finaby == null ? null : _ -> { + finaby.run(); + return null; + }); + } + + /** + * 使用锁执行指定回调 + *

+ * {@link #lock(LockType, trySupplier, Function, Function)}的可抛异常变体
+ * 运行时改为使用try-finally块,通过两个回调参数插入不同的块中执行,遇到异常会抛出 + * + * @param lockType 锁类型 + * @param run 带返回的回调 + * @param finaby 进入finally块后的回调,传入前一个回调的返回值,遇到异常传入{@code null} + * @param 要返回的数据类型 + * + * @return 回调返回的内容,遇到异常不返回 + * + * @throws Exception 异常类型根据实际运行时回调抛出决定 + * @implSpec 如果有传入 {@code finaby} 回调则返回值由{@code finaby}主导,传入{@code finaby}的值根据是否发生异常传入{@code run}的返回值或{@code null}
+ * 任意一个回调为空时直接穿透,使用上一个正确执行的值进行传递或者返回,发生异常会执行{@code finaby}但是不会返回内容 + */ + R lock(@NotNull LockType lockType, @NotNull trySupplier run, @Nullable Function finaby) throws Exception; + + /** + * 使用锁执行指定回调 + *

+ * {@link #lock(LockType, trySupplier, Function)}的简易变体 + * + * @param lockType 锁类型 + * @param run 带返回的回调 + * @param 要返回的数据类型 + * + * @return 回调返回的内容,遇到异常不返回 + * + * @throws Exception 异常类型根据实际运行时回调抛出决定 + */ + default + R lock(@NotNull LockType lockType, @NotNull trySupplier run) throws Exception + { return lock(lockType, run, null); } + + /** + * 使用锁执行指定回调 + *

+ * {@link #lock(LockType, trySupplier, Function)}的无返回变体 + * + * @param lockType 锁类型 + * @param run 执行的回调 + * @param finaby 进入finally块后的回调 + * + * @throws Exception 异常类型根据实际运行时回调抛出决定 + */ + default + void lock(@NotNull LockType lockType, @NotNull tryRunnable run, @Nullable Runnable finaby) throws Exception { + lock(lockType, () -> { + run.run(); + return null; + }, finaby == null ? null : _ -> { + finaby.run(); + return null; + }); + } + + /** + * 使用锁执行指定回调 + *

+ * {@link #lock(LockType, tryRunnable, Runnable)}的简易变体 + * + * @param lockType 锁类型 + * @param run 执行的回调 + * + * @throws Exception 异常类型根据实际运行时回调抛出决定 + */ + default + void lock(@NotNull LockType lockType, @NotNull tryRunnable run) throws Exception + { lock(lockType, run, null); } +} diff --git a/src/main/java/fybug/nulll/pdconcurrent/i/ReadWriteLock.java b/src/main/java/fybug/nulll/pdconcurrent/i/ReadWriteLock.java new file mode 100644 index 0000000..63a7d1e --- /dev/null +++ b/src/main/java/fybug/nulll/pdconcurrent/i/ReadWriteLock.java @@ -0,0 +1,203 @@ +package fybug.nulll.pdconcurrent.i; +import java.util.function.Consumer; +import java.util.function.Function; + +import fybug.nulll.pdconcurrent.e.LockType; +import fybug.nulll.pdconcurrent.fun.tryRunnable; +import fybug.nulll.pdconcurrent.fun.trySupplier; +import jakarta.annotation.Nullable; +import jakarta.validation.constraints.NotNull; + +/** + *

并发管理读写支持拓展.

+ * {@link Lock}的拓展,增加{@code read()}、{@code write()}类方法用于隐藏{@link LockType}参数 + * + * @author fybug + * @version 0.0.1 + * @see LockType#READ + * @see LockType#WRITE + * @see Lock + * @since i 0.0.1 + */ +@SuppressWarnings("unused") +public +interface ReadWriteLock extends Lock { + /** + * 使用读锁执行指定回调 + *

+ * {@link #lock(LockType, trySupplier, Function, Function)}指定读锁的变种 + * + * @param run 带返回的回调 + * @param catchby 进入catch块后的回调,传入当前异常 + * @param finaby 进入finally块后的回调,传入前两个回调的返回值 + * @param 要返回的数据类型 + * + * @return 回调返回的内容 + */ + default + R read(@NotNull trySupplier run, @Nullable Function catchby, @Nullable Function finaby) + { return lock(LockType.READ, run, catchby, finaby); } + + /** + * 使用读锁执行指定回调 + *

+ * {@link #lock(LockType, tryRunnable, Consumer, Runnable)}指定读锁的变种 + * + * @param run 执行的回调 + * @param catchby 进入catch块后的回调,传入当前异常 + * @param finaby 进入finally块后的回调 + */ + default + void read(@NotNull tryRunnable run, @Nullable Consumer catchby, @Nullable Runnable finaby) + { lock(LockType.READ, run, catchby, finaby); } + + /** + * 使用读锁执行指定回调 + *

+ * {@link #lock(LockType, trySupplier, Function)}指定读锁的变种 + * + * @param run 带返回的回调 + * @param finaby 进入finally块后的回调,传入前一个回调的返回值,遇到异常传入{@code null} + * @param 要返回的数据类型 + * + * @return 回调返回的内容,遇到异常不返回 + * + * @throws Exception 异常类型根据实际运行时回调抛出决定 + */ + default + R read(@NotNull trySupplier run, @Nullable Function finaby) throws Exception + { return lock(LockType.READ, run, finaby); } + + /** + * 使用读锁执行指定回调 + *

+ * {@link #lock(LockType, trySupplier)}指定读锁的变种 + * + * @param run 带返回的回调 + * @param 要返回的数据类型 + * + * @return 回调返回的内容 + * + * @throws Exception 异常类型根据实际运行时回调抛出决定 + */ + default + R read(@NotNull trySupplier run) throws Exception + { return lock(LockType.READ, run); } + + /** + * 使用读锁执行指定回调 + *

+ * {@link #lock(LockType, tryRunnable, Runnable)}指定读锁的变种 + * + * @param run 执行的回调 + * @param finaby 进入finally块后的回调 + * + * @throws Exception 异常类型根据实际运行时回调抛出决定 + */ + default + void read(@NotNull tryRunnable run, @Nullable Runnable finaby) throws Exception + { lock(LockType.READ, run, finaby); } + + /** + * 使用读锁执行指定回调 + *

+ * {@link #lock(LockType, tryRunnable)}指定读锁的变种 + * + * @param run 执行的回调 + * + * @throws Exception 异常类型根据实际运行时回调抛出决定 + */ + default + void read(@NotNull tryRunnable run) throws Exception + { lock(LockType.READ, run); } + + + /** + * 使用写锁执行指定回调 + *

+ * {@link #lock(LockType, trySupplier, Function, Function)}指定写锁的变种 + * + * @param run 带返回的回调 + * @param catchby 进入catch块后的回调,传入当前异常 + * @param finaby 进入finally块后的回调,传入前两个回调的返回值 + * @param 要返回的数据类型 + * + * @return 回调返回的内容 + */ + default + R write(@NotNull trySupplier run, @Nullable Function catchby, @Nullable Function finaby) + { return lock(LockType.WRITE, run, catchby, finaby); } + + /** + * 使用写锁执行指定回调 + *

+ * {@link #lock(LockType, tryRunnable, Consumer, Runnable)}指定写锁的变种 + * + * @param run 执行的回调 + * @param catchby 进入catch块后的回调,传入当前异常 + * @param finaby 进入finally块后的回调 + */ + default + void write(@NotNull tryRunnable run, @Nullable Consumer catchby, @Nullable Runnable finaby) + { lock(LockType.WRITE, run, catchby, finaby); } + + /** + * 使用写锁执行指定回调 + *

+ * {@link #lock(LockType, trySupplier, Function)}指定写锁的变种 + * + * @param run 带返回的回调 + * @param finaby 进入finally块后的回调,传入前一个回调的返回值,遇到异常传入{@code null} + * @param 要返回的数据类型 + * + * @return 回调返回的内容,遇到异常不返回 + * + * @throws Exception 异常类型根据实际运行时回调抛出决定 + */ + default + R write(@NotNull trySupplier run, @Nullable Function finaby) throws Exception + { return lock(LockType.WRITE, run, finaby); } + + /** + * 使用写锁执行指定回调 + *

+ * {@link #lock(LockType, trySupplier)}指定写锁的变种 + * + * @param run 带返回的回调 + * @param 要返回的数据类型 + * + * @return 回调返回的内容 + * + * @throws Exception 异常类型根据实际运行时回调抛出决定 + */ + default + R write(@NotNull trySupplier run) throws Exception + { return lock(LockType.WRITE, run); } + + /** + * 使用写锁执行指定回调 + *

+ * {@link #lock(LockType, tryRunnable, Runnable)}指定写锁的变种 + * + * @param run 执行的回调 + * @param finaby 进入finally块后的回调 + * + * @throws Exception 异常类型根据实际运行时回调抛出决定 + */ + default + void write(@NotNull tryRunnable run, @Nullable Runnable finaby) throws Exception + { lock(LockType.WRITE, run, finaby); } + + /** + * 使用写锁执行指定回调 + *

+ * {@link #lock(LockType, tryRunnable)}指定写锁的变种 + * + * @param run 执行的回调 + * + * @throws Exception 异常类型根据实际运行时回调抛出决定 + */ + default + void write(@NotNull tryRunnable run) throws Exception + { lock(LockType.WRITE, run); } +} diff --git a/src/main/java/fybug/nulll/pdconcurrent/i/TryLock.java b/src/main/java/fybug/nulll/pdconcurrent/i/TryLock.java new file mode 100644 index 0000000..b6d120f --- /dev/null +++ b/src/main/java/fybug/nulll/pdconcurrent/i/TryLock.java @@ -0,0 +1,142 @@ +package fybug.nulll.pdconcurrent.i; +import java.util.concurrent.locks.ReentrantLock; +import java.util.function.Consumer; +import java.util.function.Function; + +import fybug.nulll.pdconcurrent.e.LockType; +import fybug.nulll.pdconcurrent.fun.tryConsumer; +import fybug.nulll.pdconcurrent.fun.tryFunction; +import jakarta.annotation.Nullable; +import jakarta.validation.constraints.NotNull; + +/** + *

允许尝试上锁的并发管理.

+ * {@link Lock}的拓展,增加{@code trylock()}类方法用于适配需要立刻判断是否获取到锁并即刻往下执行的情况 + * + * @author fybug + * @version 0.0.1 + * @since i 0.0.1 + */ +interface TryLock { + /** + * 尝试使用锁执行指定回调 + *

+ * 可通过传入{@link LockType}指定锁的类型,但需要注意该方法并非一定能成功获取到锁,可通过{@code run}回调参数中传入的{@code boolean}判断是否成功获取到了锁
+ * 运行时自带try-catch-finally块,通过三个回调参数插入不同的块中执行
+ * 若成功获取锁则所有回调均在并发域内执行 + * + * @param lockType 锁类型 + * @param run 带返回的回调,传入参数是否获取到锁 + * @param catchby 进入catch块后的回调,传入当前异常 + * @param finaby 进入finally块后的回调,传入前两个回调的返回值 + * @param 要返回的数据类型 + * + * @return 回调返回的内容 + * + * @implSpec 该方法实现时应尽量使用如 {@link ReentrantLock#tryLock()} 之类的方法获取锁,并将是否成功获取传入{@code run}回调中
+ * 如果有传入 {@code finaby} 回调则返回值由{@code finaby}主导,传入{@code finaby}的值根据是否发生异常传入{@code run}的返回值或{@code catchby}的返回值
+ * 任意一个回调为空时直接穿透,使用上一个正确执行的值进行传递或者返回,传递值应默认为{@code null}用于应对{@code catchby}和{@code finaby}都为空但是发生了异常的情况 + */ + R trylock(@NotNull LockType lockType, @NotNull tryFunction run, @Nullable Function catchby, + @Nullable Function finaby); + + /** + * 尝试使用锁执行指定回调 + *

+ * {@link #trylock(LockType, tryFunction, Function, Function)}的无返回变体 + * + * @param lockType 锁类型 + * @param run 执行的回调,传入参数是否获取到锁 + * @param catchby 进入catch块后的回调,传入当前异常 + * @param finaby 进入finally块后的回调 + */ + default + void trylock(@NotNull LockType lockType, @NotNull tryConsumer run, @Nullable Consumer catchby, + @Nullable Runnable finaby) + { + trylock(lockType, b -> { + run.accept(b); + return null; + }, catchby == null ? null : e -> { + catchby.accept(e); + return null; + }, finaby == null ? null : _ -> { + finaby.run(); + return null; + }); + } + + /** + * 尝试使用锁执行指定回调 + *

+ * {@link #trylock(LockType, tryFunction, Function, Function)}的可抛异常变体
+ * 运行时改为使用try-finally块,通过两个回调参数插入不同的块中执行,遇到异常会抛出 + * + * @param lockType 锁类型 + * @param run 带返回的回调,传入参数是否获取到锁 + * @param finaby 进入finally块后的回调,传入前两个回调的返回值,遇到异常传入{@code null} + * @param 要返回的数据类型 + * + * @return 回调返回的内容,遇到异常不返回 + * + * @throws Exception 异常类型根据实际运行时回调抛出决定 + * @implSpec 该方法实现时应尽量使用如 {@link ReentrantLock#tryLock()} 之类的方法获取锁,并将是否成功获取传入{@code run}回调中
+ * 如果有传入 {@code finaby} 回调则返回值由{@code finaby}主导,传入{@code finaby}的值根据是否发生异常传入{@code run}的返回值或{@code catchby}的返回值
+ * 任意一个回调为空时直接穿透,使用上一个正确执行的值进行传递或者返回,传递值应默认为{@code null}用于应对{@code catchby}和{@code finaby}都为空但是发生了异常的情况 + */ + R trylock(@NotNull LockType lockType, @NotNull tryFunction run, @Nullable Function finaby) + throws Exception; + + /** + * 尝试使用锁执行指定回调 + *

+ * {@link #trylock(LockType, tryFunction, Function)}的简易变体 + * + * @param lockType 锁类型 + * @param run 带返回的回调,传入参数是否获取到锁 + * @param 要返回的数据类型 + * + * @return 回调返回的内容,遇到异常不返回 + * + * @throws Exception 异常类型根据实际运行时回调抛出决定 + */ + default + R trylock(@NotNull LockType lockType, @NotNull tryFunction run) throws Exception + { return trylock(lockType, run, null); } + + /** + * 尝试使用锁执行指定回调 + *

+ * {@link #trylock(LockType, tryFunction, Function)}的无返回变体 + * + * @param lockType 锁类型 + * @param run 执行的回调,传入参数是否获取到锁 + * @param finaby 进入finally块后的回调 + * + * @throws Exception 异常类型根据实际运行时回调抛出决定 + */ + default + void trylock(@NotNull LockType lockType, @NotNull tryConsumer run, @Nullable Runnable finaby) throws Exception { + trylock(lockType, b -> { + run.accept(b); + return null; + }, finaby == null ? null : _ -> { + finaby.run(); + return null; + }); + } + + /** + * 尝试使用锁执行指定回调 + *

+ * {@link #trylock(LockType, tryConsumer, Runnable)}的简易变体 + * + * @param lockType 锁类型 + * @param run 带返回的回调,传入参数是否获取到锁 + * + * @throws Exception 异常类型根据实际运行时回调抛出决定 + */ + default + void trylock(@NotNull LockType lockType, @NotNull tryConsumer run) throws Exception + { trylock(lockType, run, null); } +} diff --git a/src/main/java/fybug/nulll/pdconcurrent/i/TryReadWriteLock.java b/src/main/java/fybug/nulll/pdconcurrent/i/TryReadWriteLock.java new file mode 100644 index 0000000..a3ff383 --- /dev/null +++ b/src/main/java/fybug/nulll/pdconcurrent/i/TryReadWriteLock.java @@ -0,0 +1,204 @@ +package fybug.nulll.pdconcurrent.i; +import java.util.function.Consumer; +import java.util.function.Function; + +import fybug.nulll.pdconcurrent.e.LockType; +import fybug.nulll.pdconcurrent.fun.tryConsumer; +import fybug.nulll.pdconcurrent.fun.tryFunction; +import jakarta.annotation.Nullable; +import jakarta.validation.constraints.NotNull; + +/** + *

TryLock 读写支持拓展.

+ * {@link TryLock}的拓展,增加{@code tryread()}、{@code trywrite()}类方法用于隐藏{@link LockType}参数 + * + * @author fybug + * @version 0.0.1 + * @see LockType#READ + * @see LockType#WRITE + * @see TryLock + * @since i 0.0.1 + */ +@SuppressWarnings("unused") +public +interface TryReadWriteLock extends TryLock { + /** + * 尝试使用读锁执行指定回调 + *

+ * {@link #trylock(LockType, tryFunction, Function, Function)}指定读锁的变种 + * + * @param run 带返回的回调,传入参数是否获取到锁 + * @param catchby 进入catch块后的回调,传入当前异常 + * @param finaby 进入finally块后的回调,传入前两个回调的返回值 + * @param 要返回的数据类型 + * + * @return 回调返回的内容 + */ + default + R tryread(@NotNull tryFunction run, @Nullable Function catchby, + @Nullable Function finaby) + { return trylock(LockType.READ, run, catchby, finaby); } + + /** + * 尝试使用读锁执行指定回调 + *

+ * {@link #trylock(LockType, tryConsumer, Consumer, Runnable)}指定读锁的变种 + * + * @param run 执行的回调,传入参数是否获取到锁 + * @param catchby 进入catch块后的回调,传入当前异常 + * @param finaby 进入finally块后的回调 + */ + default + void tryread(@NotNull tryConsumer run, @Nullable Consumer catchby, @Nullable Runnable finaby) + { trylock(LockType.READ, run, catchby, finaby); } + + /** + * 尝试使用读锁执行指定回调 + *

+ * {@link #trylock(LockType, tryFunction, Function)}指定读锁的变种 + * + * @param run 带返回的回调,传入参数是否获取到锁 + * @param finaby 进入finally块后的回调,传入前两个回调的返回值,遇到异常传入{@code null} + * @param 要返回的数据类型 + * + * @return 回调返回的内容,遇到异常不返回 + * + * @throws Exception 异常类型根据实际运行时回调抛出决定 + */ + default + R tryread(@NotNull tryFunction run, @Nullable Function finaby) throws Exception + { return trylock(LockType.READ, run, finaby); } + + /** + * 尝试使用读锁执行指定回调 + *

+ * {@link #trylock(LockType, tryFunction)}指定读锁的变种 + * + * @param run 带返回的回调,传入参数是否获取到锁 + * @param 要返回的数据类型 + * + * @return 回调返回的内容,遇到异常不返回 + * + * @throws Exception 异常类型根据实际运行时回调抛出决定 + */ + default + R tryread(@NotNull tryFunction run) throws Exception + { return trylock(LockType.READ, run); } + + /** + * 尝试使用读锁执行指定回调 + *

+ * {@link #trylock(LockType, tryConsumer, Runnable)}指定读锁的变种 + * + * @param run 执行的回调,传入参数是否获取到锁 + * @param finaby 进入finally块后的回调 + * + * @throws Exception 异常类型根据实际运行时回调抛出决定 + */ + default + void tryread(@NotNull tryConsumer run, @Nullable Runnable finaby) throws Exception + { trylock(LockType.READ, run, finaby); } + + /** + * 尝试使用读锁执行指定回调 + *

+ * {@link #trylock(LockType, tryConsumer)}指定读锁的变种 + * + * @param run 带返回的回调,传入参数是否获取到锁 + * + * @throws Exception 异常类型根据实际运行时回调抛出决定 + */ + default + void tryread(@NotNull tryConsumer run) throws Exception + { trylock(LockType.READ, run); } + + /** + * 尝试使用写锁执行指定回调 + *

+ * {@link #trylock(LockType, tryFunction, Function, Function)}指定写锁的变种 + * + * @param run 带返回的回调,传入参数是否获取到锁 + * @param catchby 进入catch块后的回调,传入当前异常 + * @param finaby 进入finally块后的回调,传入前两个回调的返回值 + * @param 要返回的数据类型 + * + * @return 回调返回的内容 + */ + default + R trywrite(@NotNull tryFunction run, @Nullable Function catchby, + @Nullable Function finaby) + { return trylock(LockType.WRITE, run, catchby, finaby); } + + /** + * 尝试使用写锁执行指定回调 + *

+ * {@link #trylock(LockType, tryConsumer, Consumer, Runnable)}指定写锁的变种 + * + * @param run 执行的回调,传入参数是否获取到锁 + * @param catchby 进入catch块后的回调,传入当前异常 + * @param finaby 进入finally块后的回调 + */ + default + void trywrite(@NotNull tryConsumer run, @Nullable Consumer catchby, @Nullable Runnable finaby) + { trylock(LockType.WRITE, run, catchby, finaby); } + + /** + * 尝试使用写锁执行指定回调 + *

+ * {@link #trylock(LockType, tryFunction, Function)}指定写锁的变种 + * + * @param run 带返回的回调,传入参数是否获取到锁 + * @param finaby 进入finally块后的回调,传入前两个回调的返回值,遇到异常传入{@code null} + * @param 要返回的数据类型 + * + * @return 回调返回的内容,遇到异常不返回 + * + * @throws Exception 异常类型根据实际运行时回调抛出决定 + */ + default + R trywrite(@NotNull tryFunction run, @Nullable Function finaby) throws Exception + { return trylock(LockType.WRITE, run, finaby); } + + /** + * 尝试使用写锁执行指定回调 + *

+ * {@link #trylock(LockType, tryFunction)}指定写锁的变种 + * + * @param run 带返回的回调,传入参数是否获取到锁 + * @param 要返回的数据类型 + * + * @return 回调返回的内容,遇到异常不返回 + * + * @throws Exception 异常类型根据实际运行时回调抛出决定 + */ + default + R trywrite(@NotNull tryFunction run) throws Exception + { return trylock(LockType.WRITE, run); } + + /** + * 尝试使用写锁执行指定回调 + *

+ * {@link #trylock(LockType, tryConsumer, Runnable)}指定写锁的变种 + * + * @param run 执行的回调,传入参数是否获取到锁 + * @param finaby 进入finally块后的回调 + * + * @throws Exception 异常类型根据实际运行时回调抛出决定 + */ + default + void trywrite(@NotNull tryConsumer run, @Nullable Runnable finaby) throws Exception + { trylock(LockType.WRITE, run, finaby); } + + /** + * 尝试使用写锁执行指定回调 + *

+ * {@link #trylock(LockType, tryConsumer)}指定写锁的变种 + * + * @param run 带返回的回调,传入参数是否获取到锁 + * + * @throws Exception 异常类型根据实际运行时回调抛出决定 + */ + default + void trywrite(@NotNull tryConsumer run) throws Exception + { trylock(LockType.WRITE, run); } +} diff --git a/src/main/java/fybug/nulll/pdconcurrent/i/package-info.java b/src/main/java/fybug/nulll/pdconcurrent/i/package-info.java new file mode 100644 index 0000000..6ced81b --- /dev/null +++ b/src/main/java/fybug/nulll/pdconcurrent/i/package-info.java @@ -0,0 +1,9 @@ +/** + *

接口包.

+ * 提供基础功能接口与部分功能框架实现 + * + * @author fybug + * @version 0.0.1 + * @since PDConcurrent 0.1.2 + */ +package fybug.nulll.pdconcurrent.i; \ No newline at end of file diff --git a/src/main/java/fybug/nulll/pdconcurrent/ObjLock.java b/src/main/java/fybug/nulll/pdconcurrent/lock/ObjLock.java similarity index 70% rename from src/main/java/fybug/nulll/pdconcurrent/ObjLock.java rename to src/main/java/fybug/nulll/pdconcurrent/lock/ObjLock.java index 9f138ec..250ec5b 100644 --- a/src/main/java/fybug/nulll/pdconcurrent/ObjLock.java +++ b/src/main/java/fybug/nulll/pdconcurrent/lock/ObjLock.java @@ -1,7 +1,9 @@ -package fybug.nulll.pdconcurrent; +package fybug.nulll.pdconcurrent.lock; import java.util.function.Function; +import fybug.nulll.pdconcurrent.SyLock; import fybug.nulll.pdconcurrent.e.LockType; +import fybug.nulll.pdconcurrent.fun.tryFunction; import fybug.nulll.pdconcurrent.fun.trySupplier; import jakarta.annotation.Nullable; import jakarta.validation.constraints.NotNull; @@ -13,13 +15,13 @@ import lombok.Getter; *

* 使用并发管理: * {@snippet lang = java: + * import fybug.nulll.pdconcurrent.SyLock; * public final SyLock lock = new ObjLock(); * public static void main(String[] args) { * lock.read(() -> System.out.println("asd")); * }} * 不使用: * {@snippet lang = java: - * public final Object lock = new Object(); * public static void main(String[] args) { * synchronized ( lock ){ * System.out.println("asd"); @@ -27,10 +29,10 @@ import lombok.Getter; * }} * * @author fybug - * @version 0.1.0 - * @see SyLock - * @since PDConcurrent 0.0.1 + * @version 0.1.2 + * @since lock 0.0.1 */ +@SuppressWarnings("unused") @Getter public class ObjLock implements SyLock { @@ -67,7 +69,6 @@ class ObjLock implements SyLock { * @return {@inheritDoc} * * @implNote 使用 {@code synchronized( Object )} 实现的隐式并发域 - * @see SyLock#lock(LockType, trySupplier, Function, Function) * @since 0.1.0 */ @Override @@ -121,12 +122,11 @@ class ObjLock implements SyLock { * @return {@inheritDoc} * * @implNote 使用 {@code synchronized( Object )} 实现的隐式并发域 - * @see SyLock#trylock(LockType, trySupplier, Function) - * @since 0.1.0 + * @since 0.1.2 */ @Override public - R trylock(@NotNull LockType lockType, @NotNull trySupplier run, @Nullable Function finaby) throws Exception { + R lock(@NotNull LockType lockType, @NotNull trySupplier run, @Nullable Function finaby) throws Exception { R o = null; // 不上锁 if ( lockType == LockType.NOLOCK ) { @@ -153,4 +153,42 @@ class ObjLock implements SyLock { } return o; } + + /** + * {@inheritDoc} + * + * @param lockType {@inheritDoc} + * @param run {@inheritDoc} + * @param catchby {@inheritDoc} + * @param finaby {@inheritDoc} + * @param {@inheritDoc} + * + * @return {@inheritDoc} + * + * @since 0.1.2 + */ + @Override + public + R trylock(@NotNull LockType lockType, @NotNull tryFunction run, @Nullable Function catchby, + @Nullable Function finaby) + { return lock(lockType, () -> run.apply(true), catchby, finaby); } + + /** + * {@inheritDoc} + * + * @param lockType {@inheritDoc} + * @param run {@inheritDoc} + * @param finaby {@inheritDoc} + * @param {@inheritDoc} + * + * @return {@inheritDoc} + * + * @throws Exception {@inheritDoc} + * @since 0.1.2 + */ + @Override + public + R trylock(@NotNull LockType lockType, @NotNull tryFunction run, @Nullable Function finaby) + throws Exception + { return lock(lockType, () -> run.apply(true), finaby); } } diff --git a/src/main/java/fybug/nulll/pdconcurrent/RWLock.java b/src/main/java/fybug/nulll/pdconcurrent/lock/RWLock.java similarity index 42% rename from src/main/java/fybug/nulll/pdconcurrent/RWLock.java rename to src/main/java/fybug/nulll/pdconcurrent/lock/RWLock.java index e5ef8d5..ea25e36 100644 --- a/src/main/java/fybug/nulll/pdconcurrent/RWLock.java +++ b/src/main/java/fybug/nulll/pdconcurrent/lock/RWLock.java @@ -1,19 +1,19 @@ -package fybug.nulll.pdconcurrent; +package fybug.nulll.pdconcurrent.lock; +import java.util.LinkedList; +import java.util.concurrent.atomic.AtomicLong; import java.util.concurrent.locks.Condition; import java.util.concurrent.locks.ReentrantReadWriteLock; -import java.util.function.Function; import fybug.nulll.pdconcurrent.e.LockType; -import fybug.nulll.pdconcurrent.fun.trySupplier; -import jakarta.annotation.Nullable; +import fybug.nulll.pdconcurrent.i.AbstractSyLock; import jakarta.validation.constraints.NotNull; import lombok.Getter; /** *

使用{@link ReentrantReadWriteLock}实现的并发管理.

* 使用{@link ReentrantReadWriteLock}实现并发域,读写锁均为标准实现,支持通过{@link #toread()}进行锁降级
- * 使用了可中断的上锁操作{@link ReentrantReadWriteLock.ReadLock#lockInterruptibly()}和{@link ReentrantReadWriteLock.WriteLock#lockInterruptibly()}
- * 支持使用{@link #newReadCondition()}{@link #newWriteCondition()}获取{@link Condition},通过{@link #isLocked()}{@link #isWriteLocked()}{@link #isReadLocked()}检查是否被占用
+ * 使用可中断的上锁操作{@link ReentrantReadWriteLock.ReadLock#lockInterruptibly()}和{@link ReentrantReadWriteLock.WriteLock#lockInterruptibly()}实现上锁
+ * 支持使用{@link #newReadCondition()}{@link #newWriteCondition()}获取{@link Condition} *

* 使用并发管理: * {@snippet lang = java: @@ -46,17 +46,16 @@ import lombok.Getter; * }} * * @author fybug - * @version 0.1.0 - * @see SyLock - * @see LockType + * @version 0.1.1 * @see ReentrantReadWriteLock * @see ReentrantReadWriteLock.ReadLock * @see ReentrantReadWriteLock.WriteLock - * @since PDConcurrent 0.0.1 + * @since lock 0.0.1 */ +@SuppressWarnings("unused") @Getter public -class RWLock implements SyLock { +class RWLock extends AbstractSyLock { /** 锁 */ private final ReentrantReadWriteLock LOCK; /** 读锁 */ @@ -65,12 +64,22 @@ class RWLock implements SyLock { private final ReentrantReadWriteLock.WriteLock Write_LOCK; /** * 每个线程的锁状态记录 - *

- * 不上锁为{@code null}
- * 读锁为{@code 1}
- * 写锁为{@code 2} + * + * @see LockType + */ + private final ThreadLocal> LOCK_STATE = new ThreadLocal<>(); + /** + * 读锁计数 + * + * @since 0.1.1 */ - private final ThreadLocal LOCK_STATE = new ThreadLocal<>(); + private final AtomicLong READ_LOCK_COUNTER = new AtomicLong(); + /** + * 写锁计数 + * + * @since 0.1.1 + */ + private final AtomicLong WRITE_LOCK_COUNTER = new AtomicLong(); /** * 构建并发管理 @@ -103,140 +112,134 @@ class RWLock implements SyLock { } /** - * {@inheritDoc} + * 获取当前线程锁记录 * - * @param lockType {@inheritDoc} - * @param run {@inheritDoc} - * @param catchby {@inheritDoc} - * @param finaby {@inheritDoc} - * @param {@inheritDoc} + * @return 锁类型列表 * - * @return {@inheritDoc} - * - * @implNote 使用 {@link ReentrantReadWriteLock} 实现的并发域,上锁通过{@link #tolock(LockType)}进行 - * @see SyLock#lock(LockType, trySupplier, Function, Function) - * @see #tolock(LockType) - * @see #tounlock() - * @since 0.1.0 + * @since 0.1.1 */ - @Override - public - R lock(@NotNull LockType lockType, @NotNull trySupplier run, @Nullable Function catchby, - @Nullable Function finaby) - { - R o = null; - // 清空当前线程的状态 - LOCK_STATE.remove(); - // 防止finally内的回调抛异常 - try { - try { - // 上锁 - tolock(lockType); - // 主要内容 - o = run.get(); - } catch ( Exception e ) { - // 异常处理 - if ( catchby != null ) - o = catchby.apply(e); - } finally { - // 收尾 - if ( finaby != null ) - o = finaby.apply(o); - } - } finally { - // 解锁 - tounlock(); + @NotNull + private + LinkedList getCurrentThreadLockState() { + // 获取记录 + var l = LOCK_STATE.get(); + // 保证记录存在 + if ( l == null ) { + l = new LinkedList<>(); + LOCK_STATE.set(l); } - return o; + return l; } /** * {@inheritDoc} * * @param lockType {@inheritDoc} - * @param run {@inheritDoc} - * @param finaby {@inheritDoc} - * @param {@inheritDoc} - * - * @return {@inheritDoc} * - * @implNote 使用 {@link ReentrantReadWriteLock} 实现的并发域,上锁通过{@link #tolock(LockType)}进行 - * @see SyLock#trylock(LockType, trySupplier, Function) - * @see #tolock(LockType) - * @see #tounlock() - * @since 0.1.0 + * @throws Exception {@inheritDoc} + * @implNote 使用 {@link ReentrantReadWriteLock} 实现的并发域,使用了{@code lockInterruptibly()}进行可中断的上锁操作
+ * 会记录本次锁类型并记录读写锁的计数 + * @since 0.1.1 */ @Override - public - R trylock(@NotNull LockType lockType, @NotNull trySupplier run, @Nullable Function finaby) throws Exception { - R o = null; - // 清空当前线程的状态 - LOCK_STATE.remove(); - // 防止finally内的回调抛异常 - try { - try { - // 上锁 - tolock(lockType); - // 主要内容 - o = run.get(); - } finally { - // 收尾 - if ( finaby != null ) - o = finaby.apply(o); + protected + void lock(@NotNull LockType lockType) throws InterruptedException { + // 获取记录列表 + var l = getCurrentThreadLockState(); + // 检查锁类型进行上锁,并更新对应锁计数 + if ( lockType != LockType.NOLOCK ) { + if ( lockType == LockType.READ ) { + Read_LOCK.lockInterruptibly(); + READ_LOCK_COUNTER.getAndIncrement(); + } else if ( lockType == LockType.WRITE ) { + Write_LOCK.lockInterruptibly(); + WRITE_LOCK_COUNTER.getAndIncrement(); } - } finally { - // 解锁 - tounlock(); + // 记录本次锁类型 + l.add(lockType); + } else if ( l.isEmpty() ) { + LOCK_STATE.remove(); } - return o; } /** - * 根据指定类型上锁 - *

- * 使用了可中断的上锁操作{@link ReentrantReadWriteLock.ReadLock#lockInterruptibly()}和{@link ReentrantReadWriteLock.WriteLock#lockInterruptibly()}
- * 同时更新{@link #LOCK_STATE}记录 + * {@inheritDoc} * - * @param lockType 锁类型 + * @param lockType {@inheritDoc} * - * @throws InterruptedException 上锁过程中被中断 - * @see #LOCK_STATE - * @see LockType - * @since 0.1.0 + * @return {@inheritDoc} + * + * @implNote 使用 {@link ReentrantReadWriteLock} 实现的并发域,使用了{@code trylock()}实现
+ * 会记录本次锁类型并记录读写锁的计数 + * @since 0.1.1 */ - private - void tolock(@NotNull LockType lockType) throws InterruptedException { + @Override + protected + boolean trylock(@NotNull LockType lockType) { + // 获取记录列表 + var l = getCurrentThreadLockState(); + // 是否成功 + boolean success = false; + + // 检查锁类型并上锁 if ( lockType != LockType.NOLOCK ) { - if ( lockType == LockType.READ ) { - // 读锁 - Read_LOCK.lockInterruptibly(); - LOCK_STATE.set((short) 1); - } else if ( lockType == LockType.WRITE ) { - // 写锁 - Write_LOCK.lockInterruptibly(); - LOCK_STATE.set((short) 2); - } + if ( lockType == LockType.READ ) + success = Read_LOCK.tryLock(); + else if ( lockType == LockType.WRITE ) + success = Write_LOCK.tryLock(); + } + // 是否成功 + if ( success ) { + // 记录本次锁类型 + l.add(lockType); + // 更新对应锁计数 + if ( lockType == LockType.READ ) + READ_LOCK_COUNTER.getAndIncrement(); + else //noinspection ConstantValue + if ( lockType == LockType.WRITE ) + WRITE_LOCK_COUNTER.getAndIncrement(); + } else if ( l.isEmpty() ) { + LOCK_STATE.remove(); } + + return success; } /** - * 根据状态解锁 - *

- * 根据{@link #LOCK_STATE}的状态调用对应的解锁动作
- * 成功后清空{@link #LOCK_STATE}内容 + * {@inheritDoc} * - * @see #LOCK_STATE - * @since 0.1.0 + * @implNote 通过 {@link #LOCK_STATE} 检查当前线程是否持有锁,持有时才会运行{@code unlock()}
+ * 会更新读写锁的计数 + * @since 0.1.1 */ - private - void tounlock() { - // 根据实际状态解锁 - if ( LOCK_STATE.get() == 1 ) + @Override + public + void unlock() { + // 获取记录列表 + var l = LOCK_STATE.get(); + // 没有记录 + if ( l == null ) + return; + // 没有上锁 + if ( l.isEmpty() ) { + LOCK_STATE.remove(); + return; + } + + // 获取最后锁类型 + var lockType = l.removeLast(); + // 检查锁类型解锁,并更新对应锁计数 + if ( lockType == LockType.READ ) { Read_LOCK.unlock(); - else if ( LOCK_STATE.get() == 2 ) + READ_LOCK_COUNTER.getAndDecrement(); + } else if ( lockType == LockType.WRITE ) { Write_LOCK.unlock(); - // 清除记录数据 - LOCK_STATE.remove(); + WRITE_LOCK_COUNTER.getAndDecrement(); + } + + // 记录清空 + if ( l.isEmpty() ) + LOCK_STATE.remove(); } /** @@ -244,18 +247,34 @@ class RWLock implements SyLock { *

* 如果当前状态为写锁则会降级为读锁,否则不进行操作 * - * @return 是否成功降级 + * @return 是否为读锁 * - * @see #LOCK_STATE * @since 0.1.0 */ public boolean toread() { - // 转为读锁 - if ( LOCK_STATE.get() == 2 ) { + // 获取记录列表 + var l = getCurrentThreadLockState(); + // 没有上锁 + if ( l.isEmpty() ) { + LOCK_STATE.remove(); + return false; + } + + // 获取最后锁类型 + var lockType = l.getLast(); + // 检查锁类型进行处理,并更新对应锁计数 + if ( lockType == LockType.READ ) + return true; + else if ( lockType == LockType.WRITE ) { + // 锁降级 Read_LOCK.lock(); Write_LOCK.unlock(); - LOCK_STATE.set((short) 1); + // 更新记录 + l.set(l.size() - 1, LockType.WRITE); + // 更新计数 + WRITE_LOCK_COUNTER.getAndDecrement(); + READ_LOCK_COUNTER.getAndIncrement(); return true; } return false; @@ -268,18 +287,19 @@ class RWLock implements SyLock { * * @since 0.1.0 */ + @Override public - boolean isLocked() { return isReadLocked() || isWriteLocked(); } + boolean isLocked() { return isWriteLocked() || isReadLocked(); } /** * 检查读锁是否被占用 * - * @return 是否被占用 + * @return 锁是否被占用,写锁被占用也会返回{@code true} * * @since 0.1.0 */ public - boolean isReadLocked() { return LOCK_STATE.get() == 1; } + boolean isReadLocked() { return isWriteLocked() || READ_LOCK_COUNTER.get() > 0; } /** * 检查写锁是否被占用 @@ -289,7 +309,64 @@ class RWLock implements SyLock { * @since 0.1.0 */ public - boolean isWriteLocked() { return LOCK_STATE.get() == 2; } + boolean isWriteLocked() { return WRITE_LOCK_COUNTER.get() > 0; } + + /** + * 检查当前线程是否持有锁 + * + * @return 当前线程是否拥有锁 + * + * @since 0.1.1 + */ + @Override + public + boolean isLockedCurrentThread() { return isWriteLockedCurrentThread() || isReadLockedCurrentThread(); } + + /** + * 检查当前线程是否持有读锁 + * + * @return 当前线程是否持有锁,持有写锁也会返回{@code true} + * + * @since 0.1.1 + */ + public + boolean isReadLockedCurrentThread() { + // 获取锁队列 + var l = LOCK_STATE.get(); + // 没有记录 + if ( l == null ) + return false; + // 没有上锁 + if ( l.isEmpty() ) { + LOCK_STATE.remove(); + return false; + } + // 检查是否占用读锁 + return l.contains(LockType.WRITE) || l.contains(LockType.READ); + } + + /** + * 检查当前线程是否持有写锁 + * + * @return 当前线程是否持有锁 + * + * @since 0.1.1 + */ + public + boolean isWriteLockedCurrentThread() { + // 获取锁队列 + var l = LOCK_STATE.get(); + // 没有记录 + if ( l == null ) + return false; + // 没有上锁 + if ( l.isEmpty() ) { + LOCK_STATE.remove(); + return false; + } + // 检查是否占用读锁 + return l.contains(LockType.WRITE); + } /** * 获取读锁{@link Condition} diff --git a/src/main/java/fybug/nulll/pdconcurrent/ReLock.java b/src/main/java/fybug/nulll/pdconcurrent/lock/ReLock.java similarity index 50% rename from src/main/java/fybug/nulll/pdconcurrent/ReLock.java rename to src/main/java/fybug/nulll/pdconcurrent/lock/ReLock.java index 8defe87..3defce9 100644 --- a/src/main/java/fybug/nulll/pdconcurrent/ReLock.java +++ b/src/main/java/fybug/nulll/pdconcurrent/lock/ReLock.java @@ -1,19 +1,17 @@ -package fybug.nulll.pdconcurrent; +package fybug.nulll.pdconcurrent.lock; import java.util.concurrent.locks.Condition; import java.util.concurrent.locks.ReentrantLock; -import java.util.function.Function; import fybug.nulll.pdconcurrent.e.LockType; -import fybug.nulll.pdconcurrent.fun.trySupplier; -import jakarta.annotation.Nullable; +import fybug.nulll.pdconcurrent.i.AbstractSyLock; import jakarta.validation.constraints.NotNull; import lombok.Getter; /** *

使用{@link ReentrantLock}实现的并发管理.

* 使用{@link ReentrantLock}实现并发域,读写锁均为同一个实现
- * 使用了可中断的上锁操作{@link ReentrantLock#lockInterruptibly()}
- * 支持使用{@link #newCondition()}获取{@link Condition},通过{@link #isLocked()}检查是否被占用 + * 使用了可中断的上锁操作{@link ReentrantLock#lockInterruptibly()}实现
+ * 支持使用{@link #newCondition()}获取{@link Condition} *

* 使用并发管理: * {@snippet lang = java: @@ -36,14 +34,14 @@ import lombok.Getter; * }} * * @author fybug - * @version 0.1.0 - * @see SyLock + * @version 0.1.1 * @see ReentrantLock - * @since PDConcurrent 0.0.1 + * @since lock 0.0.1 */ +@SuppressWarnings("unused") @Getter public -class ReLock implements SyLock { +class ReLock extends AbstractSyLock { /** 锁 */ private final ReentrantLock LOCK; @@ -77,85 +75,47 @@ class ReLock implements SyLock { * {@inheritDoc} * * @param lockType {@inheritDoc} - * @param run {@inheritDoc} - * @param catchby {@inheritDoc} - * @param finaby {@inheritDoc} - * @param {@inheritDoc} - * - * @return {@inheritDoc} * + * @throws InterruptedException 所在线程被中断 * @implNote 使用 {@link ReentrantLock} 实现的并发域,使用了{@link ReentrantLock#lockInterruptibly()}进行可中断的上锁操作 - * @see SyLock#lock(LockType, trySupplier, Function, Function) - * @since 0.1.0 + * @since 0.1.1 */ @Override - public - R lock(@NotNull LockType lockType, trySupplier run, @Nullable Function catchby, - @Nullable Function finaby) - { - R o = null; - // 防止finally内的回调抛异常 - try { - try { - // 上锁 - if ( lockType != LockType.NOLOCK ) - LOCK.lockInterruptibly(); - // 主要内容 - o = run.get(); - } catch ( Exception e ) { - // 异常处理 - if ( catchby != null ) - o = catchby.apply(e); - } finally { - // 收尾 - if ( finaby != null ) - o = finaby.apply(o); - } - } finally { - // 解锁 - if ( lockType != LockType.NOLOCK && LOCK.isLocked() ) - LOCK.unlock(); - } - return o; + protected + void lock(@NotNull LockType lockType) throws InterruptedException { + if ( lockType != LockType.NOLOCK ) + LOCK.lockInterruptibly(); } /** * {@inheritDoc} * * @param lockType {@inheritDoc} - * @param run {@inheritDoc} - * @param finaby {@inheritDoc} - * @param {@inheritDoc} * * @return {@inheritDoc} * - * @implNote 使用 {@link ReentrantLock} 实现的并发域,使用了{@link ReentrantLock#lockInterruptibly() - * @see SyLock#trylock(LockType, trySupplier, Function) - * @since 0.1.0 + * @implNote 使用 {@link ReentrantLock} 实现的并发域,使用了{@link ReentrantLock#tryLock()}实现 + * @since 0.1.1 + */ + @Override + protected + boolean trylock(@NotNull LockType lockType) { + if ( lockType != LockType.NOLOCK ) + return LOCK.tryLock(); + return false; + } + + /** + * {@inheritDoc} + * + * @implNote 使用 {@link ReentrantLock#isHeldByCurrentThread()} 检查当前线程是否持有锁,持有时才会运行{@link ReentrantLock#unlock()} + * @since 0.1.1 */ @Override public - R trylock(@NotNull LockType lockType, @NotNull trySupplier run, @Nullable Function finaby) throws Exception { - R o = null; - // 防止finally内的回调抛异常 - try { - try { - // 上锁 - if ( lockType != LockType.NOLOCK ) - LOCK.lockInterruptibly(); - // 主要内容 - o = run.get(); - } finally { - // 收尾 - if ( finaby != null ) - o = finaby.apply(o); - } - } finally { - // 解锁 - if ( lockType != LockType.NOLOCK && LOCK.isLocked() ) - LOCK.unlock(); - } - return o; + void unlock() { + if ( LOCK.isHeldByCurrentThread() ) + LOCK.unlock(); } /** @@ -170,10 +130,22 @@ class ReLock implements SyLock { Condition newCondition() { return LOCK.newCondition(); } /** - * 检查锁是否被占用 + * {@inheritDoc} * - * @return 是否被占用 + * @return {@inheritDoc} */ + @Override public boolean isLocked() { return LOCK.isLocked(); } + + /** + * {@inheritDoc} + * + * @return {@inheritDoc} + * + * @since 0.1.1 + */ + @Override + public + boolean isLockedCurrentThread() { return LOCK.isHeldByCurrentThread(); } } diff --git a/src/main/java/fybug/nulll/pdconcurrent/lock/package-info.java b/src/main/java/fybug/nulll/pdconcurrent/lock/package-info.java new file mode 100644 index 0000000..e2f659b --- /dev/null +++ b/src/main/java/fybug/nulll/pdconcurrent/lock/package-info.java @@ -0,0 +1,8 @@ +/** + *

各种锁的实现包.

+ * + * @author fybug + * @version 0.0.1 + * @since PDConcurrent 0.1.2 + */ +package fybug.nulll.pdconcurrent.lock; \ No newline at end of file diff --git a/src/main/java/fybug/nulll/pdconcurrent/package-info.java b/src/main/java/fybug/nulll/pdconcurrent/package-info.java index b3e8496..bcd81f6 100644 --- a/src/main/java/fybug/nulll/pdconcurrent/package-info.java +++ b/src/main/java/fybug/nulll/pdconcurrent/package-info.java @@ -5,7 +5,7 @@ * 附带{@code try***}的功能接口包{@link fybug.nulll.pdconcurrent.fun},在java原有的功能接口的基础上允许抛出异常 * * @author fybug - * @version 0.1.1 + * @version 0.1.2 * @since JDK 23+ */ package fybug.nulll.pdconcurrent; \ No newline at end of file -- Gitee From 6326ef2d69f463262a0002d64cb5694da2c59106 Mon Sep 17 00:00:00 2001 From: fybug <1006291762@qq.com> Date: Fri, 14 Feb 2025 00:01:34 +0800 Subject: [PATCH 2/2] =?UTF-8?q?=E6=9B=B4=E6=96=B0=E6=96=87=E6=A1=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index f387e90..6b083dc 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,3 @@ -

Icon # PDConcurrent @@ -33,7 +32,7 @@ public static void main(String[] args) { lock.read(() -> { // 并发域代码内容 - [return null;]? // 可选择是否返回 + return null; // 可选择是否返回 }); } ``` @@ -56,11 +55,13 @@ void main(String[] args) { // 使用 lock.read(() -> { // 并发域代码内容 + return null; }); // 不使用 - synchronized ( new Object() ){ + synchronized ( lock ){ // 并发域代码内容 + return null; } } @@ -70,8 +71,6 @@ void main(String[] args) { 支持使用`newCondition()`获取`Condition`对象 -支持通过`isLocked()`检查是否被占用 - ```java public static void main(String[] args) { -- Gitee