WEBVTT

1
00:00:00.080 --> 00:00:02.399
<v Speaker 1>Every time you run a Java app that you know,

2
00:00:02.480 --> 00:00:05.080
<v Speaker 1>pulls data from a network, updates a user interface, and

3
00:00:05.200 --> 00:00:07.719
<v Speaker 1>writes to a database, all at the exact same time.

4
00:00:08.599 --> 00:00:14.000
<v Speaker 1>You're relying on this this incredibly high stakes traffic control system,

5
00:00:14.640 --> 00:00:17.079
<v Speaker 1>and it's operating at the microsecond.

6
00:00:16.519 --> 00:00:19.079
<v Speaker 2>Level, right, Yeah, it's happening so fast we just completely

7
00:00:19.120 --> 00:00:20.079
<v Speaker 2>ignore it exactly.

8
00:00:21.039 --> 00:00:24.280
<v Speaker 1>So today we are diving straight into the rulebook for

9
00:00:24.320 --> 00:00:27.800
<v Speaker 1>that infrastructure. We're looking at excerpts from the Java nine

10
00:00:27.839 --> 00:00:32.280
<v Speaker 1>Concurrency Cookbook by Javier Fernandez Gonzales.

11
00:00:31.839 --> 00:00:34.399
<v Speaker 2>Which is a fantastic resource by the way.

12
00:00:34.439 --> 00:00:37.479
<v Speaker 1>Oh. Absolutely. The mission for this deep dive is to

13
00:00:37.560 --> 00:00:41.679
<v Speaker 1>extract those core aha moments about multitasking and code. We

14
00:00:41.759 --> 00:00:45.520
<v Speaker 1>want to understand how systems share resources, prevent deadlocks, and

15
00:00:45.679 --> 00:00:48.640
<v Speaker 1>you know, avoid just totally corrupting data when thousands of

16
00:00:48.679 --> 00:00:49.719
<v Speaker 1>operations collide.

17
00:00:50.000 --> 00:00:52.560
<v Speaker 2>It really is a complex logistical operation. I mean, we

18
00:00:52.640 --> 00:00:55.759
<v Speaker 2>just take for granted that a background thread downloading a

19
00:00:55.799 --> 00:00:59.000
<v Speaker 2>file isn't going to somehow you know, overwrite the memory

20
00:00:59.039 --> 00:01:00.960
<v Speaker 2>space being used by the front end interface.

21
00:01:01.000 --> 00:01:02.560
<v Speaker 1>Yeah, that would be a disaster.

22
00:01:02.600 --> 00:01:07.519
<v Speaker 2>Total disaster. So understanding how it all works requires breaking

23
00:01:07.560 --> 00:01:10.719
<v Speaker 2>down how the operating system and the Java virtual machine

24
00:01:11.280 --> 00:01:14.400
<v Speaker 2>actually manage execution behind the scenes.

25
00:01:14.159 --> 00:01:16.599
<v Speaker 1>Right, And I think that starts with distinguishing between the

26
00:01:16.640 --> 00:01:21.560
<v Speaker 1>illusion of simultaneous execution and well, actual simultaneous execution.

27
00:01:21.680 --> 00:01:24.120
<v Speaker 2>Concurrency versus parallelism.

28
00:01:23.560 --> 00:01:27.560
<v Speaker 1>Exactly because in an older single core processor, the system

29
00:01:27.680 --> 00:01:31.799
<v Speaker 1>is executing concurrently, but it's not actually parallel. It's time slicing.

30
00:01:31.959 --> 00:01:32.840
<v Speaker 2>Yeah, it's a NAT trick.

31
00:01:33.000 --> 00:01:35.879
<v Speaker 1>It is. The OS scheduler is pulling one task onto

32
00:01:35.920 --> 00:01:38.640
<v Speaker 1>the CPU, letting it run for a tiny fraction of

33
00:01:38.640 --> 00:01:41.239
<v Speaker 1>a millisecond, saving its state, and then swapping in the

34
00:01:41.280 --> 00:01:41.719
<v Speaker 1>next task.

35
00:01:41.920 --> 00:01:45.319
<v Speaker 2>And that context switching happens so incredibly fast that human

36
00:01:45.359 --> 00:01:48.640
<v Speaker 2>perception just registers it as simultaneous. You think it's happening

37
00:01:48.640 --> 00:01:49.640
<v Speaker 2>at the same time, but it's not.

38
00:01:49.879 --> 00:01:51.840
<v Speaker 1>Okay, let's unpack this for a second. It's kind of

39
00:01:51.879 --> 00:01:55.920
<v Speaker 1>like a chef in a kitchen. Concurrency is one chef

40
00:01:56.040 --> 00:01:59.680
<v Speaker 1>rapidly switching between chopping onions and stirring soup like chopster chopster,

41
00:02:00.280 --> 00:02:02.719
<v Speaker 1>But parallelism is having two separate chefs.

42
00:02:02.959 --> 00:02:05.319
<v Speaker 2>That's a great way to look at it. Because parallelism

43
00:02:05.599 --> 00:02:11.280
<v Speaker 2>strictly requires a multicore architecture, you have multiple execution pipelines

44
00:02:11.599 --> 00:02:14.840
<v Speaker 2>physically processing different instructions at the exact same.

45
00:02:14.759 --> 00:02:17.039
<v Speaker 1>Clock cycle two actual chefs, right.

46
00:02:17.319 --> 00:02:20.599
<v Speaker 2>But regardless of whether the hardware is single core or multicore,

47
00:02:21.280 --> 00:02:25.280
<v Speaker 2>the software unit of execution within a Java process is the.

48
00:02:25.240 --> 00:02:27.919
<v Speaker 1>Thread, and the source material really breaks down the fixed

49
00:02:27.960 --> 00:02:30.719
<v Speaker 1>attributes of these threads, like you've got an immutable ID,

50
00:02:31.240 --> 00:02:33.879
<v Speaker 1>a name, a status, and a priority level from one to.

51
00:02:33.840 --> 00:02:35.599
<v Speaker 2>Ten, which is where a lot of people get tripped up.

52
00:02:35.639 --> 00:02:38.960
<v Speaker 1>Oh for sure, because my immediate instinct as a developer,

53
00:02:39.000 --> 00:02:41.520
<v Speaker 1>if I'm trying to optimize a critical path is to

54
00:02:41.639 --> 00:02:44.319
<v Speaker 1>just assign my most important thread a priority of ten

55
00:02:44.639 --> 00:02:46.280
<v Speaker 1>and assume it'll preempt everything else.

56
00:02:46.439 --> 00:02:50.199
<v Speaker 2>That is such a common assumption. But what's fascinating here

57
00:02:50.599 --> 00:02:53.520
<v Speaker 2>is that the Java priority system is essentially just a hint.

58
00:02:53.639 --> 00:02:55.840
<v Speaker 1>Wait, just a hint, Like it doesn't force it.

59
00:02:55.840 --> 00:02:59.199
<v Speaker 2>Not at all. You are basically signaling to the underlying

60
00:02:59.240 --> 00:03:03.560
<v Speaker 2>operating system, whether that's Linux, Windows, Mac, OS, whatever, that

61
00:03:03.960 --> 00:03:06.439
<v Speaker 2>you'd prefer this thread to get more CPU time.

62
00:03:06.560 --> 00:03:07.520
<v Speaker 1>Ah I see.

63
00:03:07.719 --> 00:03:11.919
<v Speaker 2>However, the OS scheduler operates on its own internal algorithms.

64
00:03:12.439 --> 00:03:16.800
<v Speaker 2>It has to balance your applications threads against system level processes,

65
00:03:16.960 --> 00:03:20.039
<v Speaker 2>network interrupts, UI responsiveness.

66
00:03:19.280 --> 00:03:22.000
<v Speaker 1>So it could just ignore my Priority ten completely.

67
00:03:22.199 --> 00:03:25.000
<v Speaker 2>Yep, it might throttle your priority ten thread if it

68
00:03:25.039 --> 00:03:28.599
<v Speaker 2>detects that a Priority five thread has been starved of

69
00:03:28.680 --> 00:03:31.960
<v Speaker 2>CPU cycles for too long. It's a recommendation, not an

70
00:03:32.039 --> 00:03:33.000
<v Speaker 2>absolute mandate.

71
00:03:33.159 --> 00:03:35.240
<v Speaker 1>That makes a lot of sense. Actually, the OS has

72
00:03:35.319 --> 00:03:40.439
<v Speaker 1>to prioritize system stability over one specific Java apps request exactly,

73
00:03:40.599 --> 00:03:42.319
<v Speaker 1>So we also need to look at how these threads

74
00:03:42.319 --> 00:03:46.080
<v Speaker 1>are managed in their life cycle. The source outlines six states.

75
00:03:46.240 --> 00:03:51.159
<v Speaker 1>You've got new, runnable, blocked, waiting, timed, waiting, and terminated.

76
00:03:51.639 --> 00:03:54.719
<v Speaker 2>And the distinction that seems most critical for performance tuning,

77
00:03:54.840 --> 00:03:57.800
<v Speaker 2>especially when things go wrong, is between blocked.

78
00:03:57.439 --> 00:04:00.560
<v Speaker 1>And waiting, because both mean the thread is an executing right,

79
00:04:00.599 --> 00:04:02.039
<v Speaker 1>but the mechanical reasons are different.

80
00:04:02.120 --> 00:04:05.400
<v Speaker 2>Yeah, totally different, And this distinction dictates how you debug

81
00:04:05.400 --> 00:04:09.439
<v Speaker 2>a bottleneck. A thread enters the block state entirely against

82
00:04:09.479 --> 00:04:10.159
<v Speaker 2>its will.

83
00:04:10.039 --> 00:04:11.560
<v Speaker 1>Like it hit a wall exactly.

84
00:04:12.080 --> 00:04:14.479
<v Speaker 2>It needs to access a memory space or a block

85
00:04:14.479 --> 00:04:18.199
<v Speaker 2>of code that is currently locked by another thread, so

86
00:04:18.240 --> 00:04:20.439
<v Speaker 2>it just has to sit in the queue, burning no

87
00:04:20.560 --> 00:04:23.759
<v Speaker 2>CPU cycles, just waiting for the OS to wake it

88
00:04:23.879 --> 00:04:25.759
<v Speaker 2>up when the lock is finally released.

89
00:04:25.879 --> 00:04:26.959
<v Speaker 1>But waiting is different.

90
00:04:27.279 --> 00:04:31.720
<v Speaker 2>Waiting is a cooperative state. A thread intentionally puts itself

91
00:04:31.759 --> 00:04:34.480
<v Speaker 2>into a waiting state because it's reached a point where

92
00:04:34.519 --> 00:04:38.120
<v Speaker 2>it literally cannot proceed until a specific condition.

93
00:04:37.879 --> 00:04:40.199
<v Speaker 1>Is met, like waiting for data to arrive over a

94
00:04:40.240 --> 00:04:40.959
<v Speaker 1>network socket.

95
00:04:41.040 --> 00:04:43.399
<v Speaker 2>Spot on. Yeah, and it will only wake up when

96
00:04:43.399 --> 00:04:45.920
<v Speaker 2>another thread sends it a deliberate signal.

97
00:04:45.720 --> 00:04:48.959
<v Speaker 1>Which brings up the broader concept of thread cooperation, which

98
00:04:49.000 --> 00:04:52.079
<v Speaker 1>I find super interesting, especially when it comes to shutting

99
00:04:52.120 --> 00:04:52.560
<v Speaker 1>them down.

100
00:04:52.720 --> 00:04:54.480
<v Speaker 2>Oh yeah, thread termination is.

101
00:04:54.480 --> 00:04:57.360
<v Speaker 1>Tricky because to start a thread you just explicitly call

102
00:04:57.480 --> 00:05:00.600
<v Speaker 1>the start method. Easy. But stop them. You don't just

103
00:05:00.639 --> 00:05:02.360
<v Speaker 1>kill a thread. You call interrupt, right.

104
00:05:02.279 --> 00:05:04.560
<v Speaker 2>Which just sets a boolean flag on the thread.

105
00:05:04.879 --> 00:05:08.160
<v Speaker 1>Yeah, the thread itself has to actively check this is

106
00:05:08.279 --> 00:05:11.560
<v Speaker 1>interrupted flag, and if it's true, it throws an interrupted exception.

107
00:05:11.879 --> 00:05:14.439
<v Speaker 1>So my question is, if a thread is stuck in

108
00:05:14.480 --> 00:05:18.079
<v Speaker 1>an infinite loop, why not just have the JVM ruthlessly

109
00:05:18.199 --> 00:05:19.480
<v Speaker 1>terminate the OS thread?

110
00:05:19.560 --> 00:05:19.680
<v Speaker 2>Like?

111
00:05:20.240 --> 00:05:21.199
<v Speaker 1>Why ask politely?

112
00:05:21.560 --> 00:05:25.639
<v Speaker 2>Because ruthless termination at the OS level leads the application

113
00:05:25.720 --> 00:05:29.040
<v Speaker 2>in an unpredictable, often completely corrupted state.

114
00:05:29.120 --> 00:05:29.959
<v Speaker 1>Okay, corrupted?

115
00:05:30.000 --> 00:05:33.199
<v Speaker 2>How well? Imagine a thread is midway through a complex

116
00:05:33.279 --> 00:05:37.759
<v Speaker 2>database transaction, or it's currently holding a critical lock on

117
00:05:37.800 --> 00:05:41.000
<v Speaker 2>some shared memory. If the JVM just kills it instantly,

118
00:05:41.040 --> 00:05:42.240
<v Speaker 2>that lock is never released.

119
00:05:42.360 --> 00:05:45.319
<v Speaker 1>Oh wow, so any other thread waiting for that lock

120
00:05:45.399 --> 00:05:47.360
<v Speaker 1>is now permanently blocked forever.

121
00:05:47.879 --> 00:05:51.079
<v Speaker 2>It's a disaster. By using the interruption mechanism, you force

122
00:05:51.160 --> 00:05:54.000
<v Speaker 2>the thread to catch the exception, execute its finely blocks,

123
00:05:54.040 --> 00:05:58.079
<v Speaker 2>close open file descriptors, roll back incomplete transactions, release its locks,

124
00:05:58.079 --> 00:06:00.000
<v Speaker 2>and then exit the execution stack cleanly.

125
00:06:00.240 --> 00:06:03.199
<v Speaker 1>Okay, so it's a highly controlled shutdown protocol to protect

126
00:06:03.240 --> 00:06:05.759
<v Speaker 1>the memory state. That makes perfect sense. But there is

127
00:06:05.800 --> 00:06:08.600
<v Speaker 1>an exception to how the JVM handles thread life cycles. Right.

128
00:06:09.000 --> 00:06:10.759
<v Speaker 1>Demon threads, ah yeah.

129
00:06:11.199 --> 00:06:14.360
<v Speaker 2>Demon threads operate under a totally different set of rules.

130
00:06:14.560 --> 00:06:18.199
<v Speaker 1>They're strictly background service providers. The classic example in the

131
00:06:18.199 --> 00:06:20.759
<v Speaker 1>text is a cleaner task that just runs in an

132
00:06:20.800 --> 00:06:24.439
<v Speaker 1>infinite loop, sweeping a queue and deleting events older than

133
00:06:24.480 --> 00:06:25.199
<v Speaker 1>ten seconds.

134
00:06:25.240 --> 00:06:27.399
<v Speaker 2>Right, And because it's an infinite loop, you'd think it

135
00:06:27.399 --> 00:06:29.160
<v Speaker 2>would keep the application running forever.

136
00:06:29.759 --> 00:06:33.279
<v Speaker 1>But if it's flagged as a demon thread, the JVM

137
00:06:33.480 --> 00:06:36.959
<v Speaker 1>just doesn't care. Once all the primary user threads have

138
00:06:37.040 --> 00:06:40.360
<v Speaker 1>finished their work and terminated, the JVM will just abruptly

139
00:06:40.399 --> 00:06:43.439
<v Speaker 1>halt and exit, taking the demon threads down with it.

140
00:06:43.759 --> 00:06:46.399
<v Speaker 2>Yeah, their existence is only justified by the presence of

141
00:06:46.480 --> 00:06:50.000
<v Speaker 2>user threads. Once the user threads are gone, the JVM

142
00:06:50.079 --> 00:06:52.519
<v Speaker 2>doesn't wait for demon threads to reach a clean state.

143
00:06:52.959 --> 00:06:55.600
<v Speaker 2>It just initiates the shutdown sequence immediately.

144
00:06:55.839 --> 00:06:57.959
<v Speaker 1>Okay, so we've got all these user threads and demon

145
00:06:58.000 --> 00:07:01.480
<v Speaker 1>threads executing concurrently, constantly being swapped in and out by

146
00:07:01.480 --> 00:07:04.920
<v Speaker 1>the OS scheduler. This leads directly to the core problem

147
00:07:05.000 --> 00:07:08.319
<v Speaker 1>of concurrency, which is shared resources and race.

148
00:07:08.120 --> 00:07:09.879
<v Speaker 2>Conditions the danger zone.

149
00:07:10.079 --> 00:07:13.759
<v Speaker 1>Yes, the source uses this parking garage simulation that I love.

150
00:07:14.160 --> 00:07:17.720
<v Speaker 1>So imagine we have sensors at different gates tracking vehicles entering,

151
00:07:18.040 --> 00:07:22.199
<v Speaker 1>and they are all updating a single short variable called cash.

152
00:07:21.800 --> 00:07:24.360
<v Speaker 2>Right to track the money. And to understand why this

153
00:07:24.480 --> 00:07:27.839
<v Speaker 2>fails without concurrency controls, you have to look at what

154
00:07:27.879 --> 00:07:29.480
<v Speaker 2>happens beneath the Java code.

155
00:07:29.600 --> 00:07:32.680
<v Speaker 1>Because a simple operation like cash equals cash plus two

156
00:07:32.920 --> 00:07:35.839
<v Speaker 1>is not a single atomic instruction for the CPU, is it.

157
00:07:36.120 --> 00:07:38.759
<v Speaker 2>No, not at all. It's a multi step process. At

158
00:07:38.759 --> 00:07:41.680
<v Speaker 2>the hardware level. The CPU has to fetch the current

159
00:07:41.759 --> 00:07:45.040
<v Speaker 2>value of cash from main memory into a local CPU register,

160
00:07:45.680 --> 00:07:48.519
<v Speaker 2>then it increments the value in that register.

161
00:07:48.360 --> 00:07:51.560
<v Speaker 1>And then Finally, it writes that updated value back to

162
00:07:51.680 --> 00:07:52.759
<v Speaker 1>main memory.

163
00:07:52.480 --> 00:07:55.079
<v Speaker 2>Exactly, and that multi step reality is where the race

164
00:07:55.120 --> 00:07:55.839
<v Speaker 2>condition lives.

165
00:07:55.920 --> 00:07:57.360
<v Speaker 1>Okay, wap me through it all right.

166
00:07:57.519 --> 00:08:00.800
<v Speaker 2>Imagine sensor A and censor B both detect a car

167
00:08:01.000 --> 00:08:04.199
<v Speaker 2>at nearly the exact same microsecond. The OS scheduler gives

168
00:08:04.199 --> 00:08:07.040
<v Speaker 2>censor A a time slice. It fetches the cash value

169
00:08:07.079 --> 00:08:09.360
<v Speaker 2>let's say it's one hundred dollars into its register. Right,

170
00:08:09.680 --> 00:08:12.360
<v Speaker 2>but before it can increment and write back it's time

171
00:08:12.399 --> 00:08:15.040
<v Speaker 2>slice expires, a context switch happens.

172
00:08:15.279 --> 00:08:19.000
<v Speaker 1>Oh man, So the OS saves censor a's state and

173
00:08:19.040 --> 00:08:20.120
<v Speaker 1>swaps in censor B.

174
00:08:20.360 --> 00:08:23.560
<v Speaker 2>Yep, and censor B fetches the cash value, which is

175
00:08:23.600 --> 00:08:26.240
<v Speaker 2>still one hundred in main memory because sensor A never

176
00:08:26.319 --> 00:08:29.040
<v Speaker 2>updated it sinceor B increments it to one oh two

177
00:08:29.240 --> 00:08:30.000
<v Speaker 2>and writes it back.

178
00:08:30.160 --> 00:08:32.399
<v Speaker 1>Okay, so main memory is now one hundred and two.

179
00:08:32.639 --> 00:08:36.360
<v Speaker 2>Right, then another context switch happens. Sensor A resumes exactly

180
00:08:36.360 --> 00:08:39.159
<v Speaker 2>where it left off, with one hundred in its local register.

181
00:08:39.480 --> 00:08:41.840
<v Speaker 1>Oh no, so it increments one hundred and two and

182
00:08:41.879 --> 00:08:43.240
<v Speaker 1>writes one hundred and two back to.

183
00:08:43.200 --> 00:08:46.679
<v Speaker 2>Main memory, completely overwriting censor b's work. You just lost

184
00:08:46.720 --> 00:08:47.320
<v Speaker 2>two dollars.

185
00:08:47.440 --> 00:08:51.360
<v Speaker 1>That is wild the book actually stimulates eight sensors processing

186
00:08:51.399 --> 00:08:54.919
<v Speaker 1>thirty vehicles each at two dollars vehicle. The mathematical certainty

187
00:08:55.000 --> 00:08:56.399
<v Speaker 1>is four hundred and eighty dollars.

188
00:08:56.440 --> 00:08:59.279
<v Speaker 2>But because of those inner leaved hardware instructions, running it

189
00:08:59.279 --> 00:09:01.960
<v Speaker 2>without rules give you four hundred and fifty eight or

190
00:09:02.039 --> 00:09:04.799
<v Speaker 2>four sixty two, you're just silently losing data.

191
00:09:04.840 --> 00:09:07.200
<v Speaker 1>And imagine if this wasn't a parking garage but your

192
00:09:07.200 --> 00:09:10.279
<v Speaker 1>bank account processing simultaneous deposits and withdrawals.

193
00:09:10.360 --> 00:09:12.320
<v Speaker 2>Yeah, that's when it stops being a fun simulation and

194
00:09:12.360 --> 00:09:13.639
<v Speaker 2>becomes a massive liability.

195
00:09:13.919 --> 00:09:17.879
<v Speaker 1>Seriously. So, the fundamental fixed Java provides for this is

196
00:09:17.919 --> 00:09:21.000
<v Speaker 1>the synchronized keyword. It turns a block of code into

197
00:09:21.080 --> 00:09:24.879
<v Speaker 1>a critical section. You use an object reference like usually.

198
00:09:24.600 --> 00:09:26.840
<v Speaker 2>This as a monitor lock, right, like a key to

199
00:09:26.879 --> 00:09:27.240
<v Speaker 2>a room.

200
00:09:27.440 --> 00:09:30.600
<v Speaker 1>Exactly, if a thread wants to execute that code, it

201
00:09:30.720 --> 00:09:33.360
<v Speaker 1>must acquire the lock. If it has the lock, no

202
00:09:33.440 --> 00:09:37.600
<v Speaker 1>other thread can enter. It forces that multi step fetch

203
00:09:37.720 --> 00:09:41.000
<v Speaker 1>increment right process to happen atomically.

204
00:09:40.480 --> 00:09:43.080
<v Speaker 2>Which is great. It resolves the data corruption. Correctness always

205
00:09:43.080 --> 00:09:47.080
<v Speaker 2>has to be prioritized over performance. But and this is

206
00:09:47.120 --> 00:09:50.840
<v Speaker 2>a big but, it introduces a severe performance penalty.

207
00:09:50.559 --> 00:09:54.360
<v Speaker 1>Right because synchronized is such a blunt instrument, very blunt.

208
00:09:54.440 --> 00:09:56.759
<v Speaker 2>When you use it, you're using a very rigid, mutually

209
00:09:56.759 --> 00:09:59.639
<v Speaker 2>exclusive lock. If you have ten threads hitting that method,

210
00:09:59.679 --> 00:10:01.639
<v Speaker 2>one g it's the CPU time to execute, and the

211
00:10:01.639 --> 00:10:03.919
<v Speaker 2>other nine are forced into that blsake state we.

212
00:10:03.879 --> 00:10:05.759
<v Speaker 1>Talked about earlier, just sitting there waiting.

213
00:10:05.840 --> 00:10:08.960
<v Speaker 2>Yeah, they're descheduled by the OS, moved into a weight queue,

214
00:10:09.080 --> 00:10:11.279
<v Speaker 2>and then they have to endure the overhead of being

215
00:10:11.320 --> 00:10:14.440
<v Speaker 2>woken up and rescheduled later. You essentially destroy the throughput

216
00:10:14.440 --> 00:10:15.240
<v Speaker 2>of your application.

217
00:10:15.600 --> 00:10:19.679
<v Speaker 1>You're forcing a concurrent system to operate sequentially, and because

218
00:10:19.679 --> 00:10:22.480
<v Speaker 1>it puts so many threads to sleep, Java had to

219
00:10:22.519 --> 00:10:28.039
<v Speaker 1>evolve better traffic signals, which brings us to advanced locks right.

220
00:10:28.120 --> 00:10:32.120
<v Speaker 2>Moving beyond the native synchronized keyword using the lock interface,

221
00:10:32.759 --> 00:10:35.360
<v Speaker 2>specifically implementations like re entrant lock.

222
00:10:36.000 --> 00:10:38.559
<v Speaker 1>So how does re entrent lock fix the bluntness.

223
00:10:38.840 --> 00:10:42.840
<v Speaker 2>Well, it provides programmatic flexibility. For example, it introduces the

224
00:10:42.840 --> 00:10:43.480
<v Speaker 2>concept of.

225
00:10:43.440 --> 00:10:46.240
<v Speaker 1>Fairness, fairness like polite threads.

226
00:10:46.399 --> 00:10:50.039
<v Speaker 2>Basically, yeah, by default, locks in Java are non fair.

227
00:10:50.559 --> 00:10:52.919
<v Speaker 2>When a lock is released, the OS doesn't care which

228
00:10:52.960 --> 00:10:55.120
<v Speaker 2>block thread has been waiting the longest. It just wakes

229
00:10:55.120 --> 00:10:57.799
<v Speaker 2>one up randomly, often based on whichever is most convenient

230
00:10:57.840 --> 00:10:58.799
<v Speaker 2>for the CPU cash.

231
00:10:58.879 --> 00:11:01.080
<v Speaker 1>But with reintrent lock you can pass a true boole

232
00:11:01.159 --> 00:11:04.720
<v Speaker 1>into the constructor to enforce a fair lock. The textbook

233
00:11:04.799 --> 00:11:06.679
<v Speaker 1>uses a print que as an example.

234
00:11:06.320 --> 00:11:09.360
<v Speaker 2>Which is a perfect example because you absolutely want jobs

235
00:11:09.399 --> 00:11:11.360
<v Speaker 2>processed in the order they were submitted, right.

236
00:11:11.559 --> 00:11:14.360
<v Speaker 1>A fair lock forces the system to maintain a strict

237
00:11:14.399 --> 00:11:17.519
<v Speaker 1>first in, first out queue of waiting threads, like a

238
00:11:17.519 --> 00:11:19.000
<v Speaker 1>polite line at a coffee shop.

239
00:11:19.120 --> 00:11:22.919
<v Speaker 2>There's a trade off, though, maintaining that strict queue adds overhead.

240
00:11:23.759 --> 00:11:27.120
<v Speaker 2>The system has to track thread arrival times and orchestrate

241
00:11:27.159 --> 00:11:32.320
<v Speaker 2>the wakeups in exact order. That lowers overall throughput compared

242
00:11:32.320 --> 00:11:35.039
<v Speaker 2>to a non fare lock, where the OS can just

243
00:11:35.120 --> 00:11:36.399
<v Speaker 2>optimize for raw speed.

244
00:11:36.559 --> 00:11:39.399
<v Speaker 1>Got it, But even with re entrent lock, we still

245
00:11:39.399 --> 00:11:42.679
<v Speaker 1>have the mutual exclusion problem. Right, Only one thread gets

246
00:11:42.679 --> 00:11:43.320
<v Speaker 1>in at a time.

247
00:11:43.399 --> 00:11:43.720
<v Speaker 2>Correct.

248
00:11:43.960 --> 00:11:45.919
<v Speaker 1>So if we have a data structure that is read

249
00:11:46.080 --> 00:11:49.799
<v Speaker 1>frequently but updated rarely, locking out all the readers just

250
00:11:49.840 --> 00:11:53.519
<v Speaker 1>because one thread is currently reading seems incredibly inefficient.

251
00:11:53.559 --> 00:11:56.840
<v Speaker 2>Well, it is because multiple threads reading a variable doesn't

252
00:11:56.879 --> 00:11:59.919
<v Speaker 2>cause a race condition. Nobody is writing new data back

253
00:11:59.960 --> 00:12:01.600
<v Speaker 2>to memory, right, and.

254
00:12:01.519 --> 00:12:03.759
<v Speaker 1>That realization led to the read right lock, Yeah, which

255
00:12:03.799 --> 00:12:04.039
<v Speaker 1>is a.

256
00:12:04.000 --> 00:12:07.080
<v Speaker 2>Huge step up. It mathematically separates a lock into two

257
00:12:07.159 --> 00:12:11.600
<v Speaker 2>distinct entities. Multiple threads can acquire the read lock simultaneously.

258
00:12:10.879 --> 00:12:14.039
<v Speaker 1>So the system just keeps a counter of active readers exactly.

259
00:12:14.080 --> 00:12:16.799
<v Speaker 2>As long as there are readers, the read lock remains open.

260
00:12:17.159 --> 00:12:19.759
<v Speaker 2>But if a thread wants to modify the data, it

261
00:12:19.840 --> 00:12:20.960
<v Speaker 2>requests the right lock.

262
00:12:21.320 --> 00:12:23.600
<v Speaker 1>And what happens then? Do the readers get kicked out?

263
00:12:23.919 --> 00:12:27.360
<v Speaker 2>No, the read right lock stops admitting new readers. It

264
00:12:27.440 --> 00:12:30.399
<v Speaker 2>waits for the current active readers to finish and drop

265
00:12:30.440 --> 00:12:33.399
<v Speaker 2>that counter to zero, and then it grants exclusive access

266
00:12:33.399 --> 00:12:33.799
<v Speaker 2>to the writer.

267
00:12:34.000 --> 00:12:37.279
<v Speaker 1>Okay, and once the writ is complete, the doors open

268
00:12:37.320 --> 00:12:38.600
<v Speaker 1>for readers again exactly.

269
00:12:38.679 --> 00:12:43.080
<v Speaker 2>It massively improves throughput for read heavy operations. However, it

270
00:12:43.159 --> 00:12:46.919
<v Speaker 2>introduces a new structural vulnerability.

271
00:12:46.240 --> 00:12:47.159
<v Speaker 1>Writer starvation.

272
00:12:47.360 --> 00:12:50.519
<v Speaker 2>Yeah. Writer's starvation is a real headache, right.

273
00:12:50.480 --> 00:12:53.080
<v Speaker 1>Because if you have a high traffic system where hundreds

274
00:12:53.120 --> 00:12:56.240
<v Speaker 1>of reader threads are constantly requesting the read lock, the

275
00:12:56.279 --> 00:12:59.679
<v Speaker 1>active reader counter might never actually hit zero never, so

276
00:12:59.759 --> 00:13:02.639
<v Speaker 1>the the right thread is essentially stuck in the queue forever,

277
00:13:02.799 --> 00:13:05.240
<v Speaker 1>waiting for a break in the traffic that just never comes.

278
00:13:05.320 --> 00:13:10.000
<v Speaker 2>Exactly and to resolve that specific bottleneck. Java eight introduce

279
00:13:10.080 --> 00:13:10.799
<v Speaker 2>the stamplock.

280
00:13:11.000 --> 00:13:14.559
<v Speaker 1>Oh, this is where it gets really interesting. Stamplock introduces

281
00:13:14.600 --> 00:13:18.080
<v Speaker 1>this concept of optimistic reading, which honestly is one of

282
00:13:18.080 --> 00:13:21.039
<v Speaker 1>the most advanced mechanics in the cookbook. What does it

283
00:13:21.080 --> 00:13:23.559
<v Speaker 1>actually mean for code to be optimistic?

284
00:13:23.799 --> 00:13:26.840
<v Speaker 2>It's a brilliant shift in strategy. Let's look at how

285
00:13:26.840 --> 00:13:30.360
<v Speaker 2>it functions at the memory level. With the traditional lock,

286
00:13:30.679 --> 00:13:32.960
<v Speaker 2>a thread has to write to a shared memory location

287
00:13:33.120 --> 00:13:36.840
<v Speaker 2>to declare, hey, I hold this lock right. That right

288
00:13:36.960 --> 00:13:40.960
<v Speaker 2>operation forces the CPU to invalidate caches across other cores,

289
00:13:41.399 --> 00:13:44.080
<v Speaker 2>which is an incredibly expensive hardware operation just.

290
00:13:44.000 --> 00:13:45.480
<v Speaker 1>To say I'm reading something right.

291
00:13:46.120 --> 00:13:50.080
<v Speaker 2>The stamplock circumvents that entirely for reads. When a thread

292
00:13:50.080 --> 00:13:53.720
<v Speaker 2>calls try optimistic read, it doesn't actually acquire a lock

293
00:13:53.840 --> 00:13:56.120
<v Speaker 2>or alter the state of the lock in memory at all.

294
00:13:56.240 --> 00:13:57.440
<v Speaker 1>Wait, it doesn't lock it.

295
00:13:57.600 --> 00:14:01.320
<v Speaker 2>Nope. Instead, the stamplock we're it turns a stamp, a

296
00:14:01.360 --> 00:14:05.120
<v Speaker 2>long integer that represents the current version or sequence number

297
00:14:05.159 --> 00:14:05.960
<v Speaker 2>of the lock state.

298
00:14:06.039 --> 00:14:07.320
<v Speaker 1>Okay, so it gets a stamp.

299
00:14:07.480 --> 00:14:10.720
<v Speaker 2>Then what the thread takes that stamp reads the shared

300
00:14:10.759 --> 00:14:14.039
<v Speaker 2>data into its own local private variables and then immediately

301
00:14:14.039 --> 00:14:16.480
<v Speaker 2>calls a validate method passing in that stamp.

302
00:14:16.559 --> 00:14:19.519
<v Speaker 1>Ah. So the validate method just checks if the internal

303
00:14:19.600 --> 00:14:22.519
<v Speaker 1>version number of the stamplock has changed since the stamp

304
00:14:22.600 --> 00:14:23.399
<v Speaker 1>was issued.

305
00:14:23.399 --> 00:14:26.600
<v Speaker 2>Exactly if no other thread acquired a right lock in

306
00:14:26.639 --> 00:14:30.279
<v Speaker 2>that tiny microsecond window while you were reading, the version

307
00:14:30.320 --> 00:14:33.679
<v Speaker 2>number still matches. The validation returns true.

308
00:14:33.960 --> 00:14:37.279
<v Speaker 1>Wow, so the thread successfully read the data without ever

309
00:14:37.320 --> 00:14:41.559
<v Speaker 1>locking the system or causing cash invalidation across the CPU cores.

310
00:14:41.720 --> 00:14:45.000
<v Speaker 2>Yep, it's a gamble. It's an assumption that collisions are rare.

311
00:14:45.399 --> 00:14:48.879
<v Speaker 2>You move fast, copy the data, and validate after the fact.

312
00:14:48.960 --> 00:14:50.919
<v Speaker 1>But what if you lose the gamble. What if a

313
00:14:50.960 --> 00:14:54.799
<v Speaker 1>writer thread did acquire the right lock during your read operation, then.

314
00:14:54.759 --> 00:14:58.519
<v Speaker 2>The lock's internal version number would have incremented. Your validation fails.

315
00:14:58.840 --> 00:15:00.159
<v Speaker 2>It returns false.

316
00:15:00.120 --> 00:15:03.039
<v Speaker 1>Because your local copy of the data is potentially corrupted

317
00:15:03.039 --> 00:15:03.879
<v Speaker 1>by a partial rite.

318
00:15:04.519 --> 00:15:08.000
<v Speaker 2>So in that scenario, your thread discards the local copy

319
00:15:08.039 --> 00:15:10.600
<v Speaker 2>and falls back to a heavier traditional read lock to

320
00:15:10.679 --> 00:15:13.799
<v Speaker 2>ensure it gets clean data. But in systems with massive

321
00:15:13.840 --> 00:15:16.759
<v Speaker 2>read to write ratios, the optimistic gamble pays off so

322
00:15:16.919 --> 00:15:19.039
<v Speaker 2>often that the performance gains are just huge.

323
00:15:19.120 --> 00:15:22.279
<v Speaker 1>That is, so cool. It's a complete shift from pessimistic

324
00:15:22.279 --> 00:15:24.240
<v Speaker 1>control to optimistic validation.

325
00:15:24.679 --> 00:15:25.279
<v Speaker 2>It really is.

326
00:15:25.440 --> 00:15:25.759
<v Speaker 1>Yeah.

327
00:15:25.879 --> 00:15:29.480
<v Speaker 2>But up to this point, all these locks re entrant

328
00:15:29.799 --> 00:15:34.879
<v Speaker 2>ReadWrite stamped in moorge. They are primarily about restricting access.

329
00:15:34.600 --> 00:15:35.600
<v Speaker 1>Right, keeping threads out.

330
00:15:35.759 --> 00:15:39.840
<v Speaker 2>Yeah, but the source material also dives into coordination. Sometimes

331
00:15:39.879 --> 00:15:43.039
<v Speaker 2>threads don't just need exclusive access, They need to orchestrate

332
00:15:43.080 --> 00:15:44.720
<v Speaker 2>complex handoffs.

333
00:15:44.440 --> 00:15:49.320
<v Speaker 1>Which brings us to advanced coordination. And the foundational scenario

334
00:15:49.399 --> 00:15:51.600
<v Speaker 1>here is the producer consumer.

335
00:15:51.240 --> 00:15:54.559
<v Speaker 2>Problem write a classic computer science problem. You have a

336
00:15:54.600 --> 00:15:58.159
<v Speaker 2>shared data buffer. Producer threads compute data and insert it.

337
00:15:58.320 --> 00:16:00.879
<v Speaker 2>Consumer threads extract data and process it.

338
00:16:01.120 --> 00:16:03.679
<v Speaker 1>But they have to communicate right, Because if the buffer

339
00:16:03.799 --> 00:16:07.480
<v Speaker 1>is full, a producer shouldn't just repeatedly pull the buffer

340
00:16:07.480 --> 00:16:10.039
<v Speaker 1>in a while loop, constantly checking if they're space No.

341
00:16:10.159 --> 00:16:13.679
<v Speaker 2>That's called spin waiting. It's terrible for performance. It burns

342
00:16:13.679 --> 00:16:16.120
<v Speaker 2>CPU cycles on a core that could actually be used

343
00:16:16.120 --> 00:16:18.000
<v Speaker 2>by a consumer thread to empty the buffer.

344
00:16:18.080 --> 00:16:20.000
<v Speaker 1>So how do we fix spinwaighting?

345
00:16:20.159 --> 00:16:23.360
<v Speaker 2>Java provides the condition interface for this, usually paired with

346
00:16:23.360 --> 00:16:26.320
<v Speaker 2>a reentrant lock. When a producer sees a full buffer,

347
00:16:26.440 --> 00:16:29.919
<v Speaker 2>it calls a weight on a specific condition object.

348
00:16:29.559 --> 00:16:30.679
<v Speaker 1>And that puts it to sleep.

349
00:16:31.039 --> 00:16:34.679
<v Speaker 2>Yes, the os de schedules the thread puts it in

350
00:16:34.720 --> 00:16:38.720
<v Speaker 2>a waiting state, and crucially, it atomically releases the lock

351
00:16:39.120 --> 00:16:40.720
<v Speaker 2>so consumers can actually get in.

352
00:16:40.919 --> 00:16:44.759
<v Speaker 1>Oh that's elegant. So then a consumer thread acquires the lock,

353
00:16:44.879 --> 00:16:47.480
<v Speaker 1>pulls an item from the buffer, and it needs to

354
00:16:47.480 --> 00:16:48.600
<v Speaker 1>tell the producer right right.

355
00:16:48.679 --> 00:16:52.000
<v Speaker 2>It calls signal on that exact same condition object.

356
00:16:51.879 --> 00:16:54.200
<v Speaker 1>And that triggers the os scheduler to wake up the

357
00:16:54.200 --> 00:16:57.480
<v Speaker 1>sleeping producer threads, letting them know, hey, the state changed

358
00:16:57.679 --> 00:16:59.440
<v Speaker 1>space is available exactly.

359
00:16:59.480 --> 00:17:02.639
<v Speaker 2>It's a high maily efficient event driven handoff instead of

360
00:17:02.639 --> 00:17:03.559
<v Speaker 2>constantly checking.

361
00:17:03.679 --> 00:17:07.039
<v Speaker 1>Okay, so that's handoffs. But this coordination also extends to

362
00:17:07.200 --> 00:17:11.880
<v Speaker 1>managing pools of identical resources, which brings us to semaphores,

363
00:17:12.119 --> 00:17:15.920
<v Speaker 1>originally invented by Edsgerdikstra back in what nineteen sixty five.

364
00:17:16.000 --> 00:17:18.039
<v Speaker 2>Yeah, they've been around for a while. Because a lock

365
00:17:18.119 --> 00:17:21.039
<v Speaker 2>is binary, it's either held or it isn't. But a

366
00:17:21.079 --> 00:17:24.079
<v Speaker 2>semaphore is a counter representing a finite number of permits.

367
00:17:24.119 --> 00:17:26.799
<v Speaker 1>The book uses a multiprinter queue to illustrate this, but

368
00:17:26.839 --> 00:17:29.000
<v Speaker 1>it kind of reminds me the bouncer at a club.

369
00:17:29.200 --> 00:17:31.759
<v Speaker 2>Oh I like that? How so well, a lock.

370
00:17:31.680 --> 00:17:35.039
<v Speaker 1>Is like a VIP bathroom, one person in, one person out,

371
00:17:35.680 --> 00:17:38.759
<v Speaker 1>but a semaphore is a bouncer keeping the club capacity

372
00:17:38.759 --> 00:17:40.200
<v Speaker 1>at exactly three people.

373
00:17:40.400 --> 00:17:43.119
<v Speaker 2>That's a great analogy. So if you have three physical printers,

374
00:17:43.440 --> 00:17:45.839
<v Speaker 2>you initialize a semaphore with a permit count of.

375
00:17:45.839 --> 00:17:48.319
<v Speaker 1>Three, and when a thread wants to print, it calls

376
00:17:48.359 --> 00:17:48.799
<v Speaker 1>a choir.

377
00:17:49.000 --> 00:17:51.599
<v Speaker 2>The semaphore checks the counter. If it's greater than zero,

378
00:17:52.000 --> 00:17:54.519
<v Speaker 2>it decrements the counter and grants the permit, So.

379
00:17:54.519 --> 00:17:57.839
<v Speaker 1>The first three threads get immediate access, dropping the counter

380
00:17:57.880 --> 00:17:58.359
<v Speaker 1>to zero.

381
00:17:58.519 --> 00:18:01.200
<v Speaker 2>Right when a fourth thread calls a CHOI. The semaphore

382
00:18:01.240 --> 00:18:04.720
<v Speaker 2>sees that zero count, it blocks that four thread, puts

383
00:18:04.720 --> 00:18:06.200
<v Speaker 2>it to sleep in a queue.

384
00:18:05.920 --> 00:18:08.000
<v Speaker 1>Just waiting in line outside the club exactly.

385
00:18:08.079 --> 00:18:11.079
<v Speaker 2>It stays there until one of the active threads finishes

386
00:18:11.119 --> 00:18:12.960
<v Speaker 2>its print job and calls release.

387
00:18:12.880 --> 00:18:14.960
<v Speaker 1>Which increments the counter back to one.

388
00:18:15.079 --> 00:18:17.559
<v Speaker 2>Yes, and then the semaphore unblocks the next thread in

389
00:18:17.599 --> 00:18:20.839
<v Speaker 2>the queue and hands it the newly available permit. It

390
00:18:20.880 --> 00:18:24.759
<v Speaker 2>regulates capacity without caring about the specific identity of the

391
00:18:24.799 --> 00:18:25.640
<v Speaker 2>threads inside.

392
00:18:25.880 --> 00:18:29.039
<v Speaker 1>It's just brilliant. But I mean this raises an important question.

393
00:18:29.200 --> 00:18:33.200
<v Speaker 1>While these tools locks conditions semaphors, they give you the

394
00:18:33.279 --> 00:18:37.920
<v Speaker 1>power to organize chaos, don't They also introduce a massive vulnerability.

395
00:18:38.119 --> 00:18:39.079
<v Speaker 2>Oh you mean deadlocks?

396
00:18:39.200 --> 00:18:42.440
<v Speaker 1>Yeah, deadlocks the ultimate concurrency nightmare, they really are.

397
00:18:42.759 --> 00:18:46.000
<v Speaker 2>This happens when the coordination logic loops back on itself.

398
00:18:45.680 --> 00:18:47.680
<v Speaker 1>The circular dependency exactly.

399
00:18:48.119 --> 00:18:52.039
<v Speaker 2>Imagine thread A acquires lock x at the exact same

400
00:18:52.079 --> 00:18:54.279
<v Speaker 2>time thread B acquires lock y.

401
00:18:54.599 --> 00:18:54.960
<v Speaker 1>Okay.

402
00:18:55.279 --> 00:18:58.480
<v Speaker 2>Then thread A tries to acquire lock why to finish

403
00:18:58.559 --> 00:19:03.640
<v Speaker 2>its operation, but it's b lock A because B holds it. Meanwhile,

404
00:19:03.720 --> 00:19:06.519
<v Speaker 2>thread B tries to acquire lock X, but it's block

405
00:19:06.599 --> 00:19:07.880
<v Speaker 2>AD because A holds it.

406
00:19:08.079 --> 00:19:11.799
<v Speaker 1>Wow. So both threads under this indefinite blocked ed state.

407
00:19:11.680 --> 00:19:13.960
<v Speaker 2>Yes, neither can proceed to the point where they would

408
00:19:13.960 --> 00:19:17.680
<v Speaker 2>release their current locks. The application state just freezes. Yeah,

409
00:19:17.720 --> 00:19:20.039
<v Speaker 2>and the only resolution is an OS level termination.

410
00:19:20.240 --> 00:19:22.039
<v Speaker 1>So how do you prevent that? Is there a specific

411
00:19:22.119 --> 00:19:23.119
<v Speaker 1>Java class for it?

412
00:19:23.319 --> 00:19:27.920
<v Speaker 2>No? Unfortunately, not preventing deadlocks isn't about using a magic class.

413
00:19:28.319 --> 00:19:33.240
<v Speaker 2>It requires strict architectural discipline. Usually that means enforcing a

414
00:19:33.279 --> 00:19:36.880
<v Speaker 2>global ordering system where threads are only allowed to request

415
00:19:36.960 --> 00:19:39.359
<v Speaker 2>locks in a specific, pre defined sequence.

416
00:19:39.480 --> 00:19:41.519
<v Speaker 1>You really have to have your whole system mapped out,

417
00:19:41.880 --> 00:19:44.599
<v Speaker 1>which I guess all comes back to that incredibly high

418
00:19:44.640 --> 00:19:46.960
<v Speaker 1>stakes traffic control system we talked about at the start.

419
00:19:47.039 --> 00:19:47.480
<v Speaker 2>It does.

420
00:19:47.759 --> 00:19:50.440
<v Speaker 1>We've really traced the mechanics from the ground up today,

421
00:19:50.799 --> 00:19:53.519
<v Speaker 1>from the OS time slicing that creates the illusion of

422
00:19:53.559 --> 00:19:57.400
<v Speaker 1>concurrency to the hardware level race conditions caused by those

423
00:19:57.519 --> 00:19:59.119
<v Speaker 1>multistep memory operations.

424
00:19:59.319 --> 00:20:02.720
<v Speaker 2>Yeah, and we've seeing how synchronized stops data corruption but

425
00:20:02.839 --> 00:20:07.759
<v Speaker 2>creates massive bottle mix which force the evolution toward reintrent locks,

426
00:20:07.799 --> 00:20:11.200
<v Speaker 2>read write locks, and eventually that highly optimized stamplock.

427
00:20:11.480 --> 00:20:14.559
<v Speaker 1>And we covered how threads communicate state changes without burning

428
00:20:14.599 --> 00:20:18.960
<v Speaker 1>CPU cycles using conditions, and how they pool resources using semaphores,

429
00:20:19.319 --> 00:20:20.039
<v Speaker 1>all while.

430
00:20:19.799 --> 00:20:23.720
<v Speaker 2>Having to mathematically prove their lock ordering to avoid those deadlocks.

431
00:20:24.079 --> 00:20:27.599
<v Speaker 1>It really is the invisible infrastructure of the modern software world.

432
00:20:28.000 --> 00:20:32.079
<v Speaker 1>Every smooth, glitch free app you use today, every scalable

433
00:20:32.200 --> 00:20:35.599
<v Speaker 1>back end, high frequency trading platform, they all rely on

434
00:20:35.640 --> 00:20:40.039
<v Speaker 1>these exact rules to keep the chaos organized behind the scenes.

435
00:20:40.000 --> 00:20:44.079
<v Speaker 2>Because without these mechanisms acting as the bedrock, concurrent programming

436
00:20:44.079 --> 00:20:46.359
<v Speaker 2>would just result in cascading data corruption.

437
00:20:46.599 --> 00:20:49.920
<v Speaker 1>Absolutely, And as a final takeaway, I want to loop

438
00:20:49.960 --> 00:20:52.960
<v Speaker 1>back to the concept of the stamplock and optimistic reading

439
00:20:53.359 --> 00:20:55.880
<v Speaker 1>because in systems design, we found that assuming no one

440
00:20:55.880 --> 00:20:59.440
<v Speaker 1>else is interfering, moving fast and just validating our assumptions

441
00:20:59.480 --> 00:21:03.119
<v Speaker 1>at the end is often exponentially faster than constantly locking

442
00:21:03.119 --> 00:21:04.519
<v Speaker 1>the system down. Just in case.

443
00:21:04.720 --> 00:21:06.599
<v Speaker 2>It's really powerful paradigm shift.

444
00:21:06.759 --> 00:21:08.440
<v Speaker 1>It really is, and it makes you wonder how that

445
00:21:08.480 --> 00:21:11.880
<v Speaker 1>applies beyond the CPU when managing complex projects you're dealing

446
00:21:11.960 --> 00:21:14.920
<v Speaker 1>with chaotic parallel workflows in our own lives. Do we

447
00:21:14.960 --> 00:21:18.160
<v Speaker 1>overuse the equivalent of a pessimistic lock? Do we bottleneck

448
00:21:18.200 --> 00:21:20.960
<v Speaker 1>our own throughput by trying to tightly control and restrict

449
00:21:21.039 --> 00:21:23.759
<v Speaker 1>every single variable, that's a great question. Or is there

450
00:21:23.839 --> 00:21:26.880
<v Speaker 1>room to adopt an optimistic read, you know, operating on

451
00:21:26.920 --> 00:21:30.160
<v Speaker 1>the assumption that the state hasn't changed, doing the work

452
00:21:30.200 --> 00:21:33.039
<v Speaker 1>and just building in a quick validation check at the end.

453
00:21:33.480 --> 00:21:35.960
<v Speaker 1>Something to ponder next time you're trying to multitask in

454
00:21:36.000 --> 00:21:38.400
<v Speaker 1>your own life. Thanks for diving deep with us today.
