1 00:00:00,390 --> 00:00:03,570 We can use Re entrant locks to enforce thread safety. 2 00:00:07,710 --> 00:00:10,950 Critical sections of your code must be accessed in serial. 3 00:00:14,400 --> 00:00:17,820 When multithreading, you need to lock critical sections of your code. 4 00:00:22,390 --> 00:00:27,250 And so in this lesson, you will use a re-engagement lock to lock a critical part of your code. 5 00:00:30,590 --> 00:00:34,940 First things first opened up the folder for this lesson by following this path in your course resources. 6 00:00:40,190 --> 00:00:45,710 First, let's talk about what a race condition is, a race condition is an incorrect computation that 7 00:00:45,710 --> 00:00:50,300 results from too many threads trying to update or access the same resource. 8 00:00:55,120 --> 00:00:59,320 And so critical code is code that is vulnerable to race conditions. 9 00:01:04,830 --> 00:01:09,870 That being said, your app is going to be vulnerable to race conditions if many threads are able to 10 00:01:09,870 --> 00:01:12,620 access or update critical code at the same time. 11 00:01:17,470 --> 00:01:25,360 So open up that Java here we have a task method that increments a counter variable 10000 times in a 12 00:01:25,360 --> 00:01:26,810 single threaded context. 13 00:01:26,830 --> 00:01:29,050 This code is going to work just fine. 14 00:01:30,000 --> 00:01:35,340 And so in Maine, if I happen to call this really long task twice the task task. 15 00:01:38,650 --> 00:01:42,250 You would expect that after printing the counter, we should get 20000. 16 00:01:43,760 --> 00:01:44,480 Run our code. 17 00:01:48,000 --> 00:01:53,670 And you would be correct again in a single threaded context right now, we're just using one thread. 18 00:01:53,790 --> 00:01:55,570 This is pretty basic stuff. 19 00:01:55,590 --> 00:01:57,350 Everything is just running on the main thread. 20 00:01:57,360 --> 00:01:59,250 The first loop will call it task. 21 00:01:59,250 --> 00:02:01,500 One keeps incrementing until 10000. 22 00:02:01,890 --> 00:02:05,160 The second loop will call it task two increments until 20000. 23 00:02:05,580 --> 00:02:06,810 This is pretty basic stuff. 24 00:02:07,590 --> 00:02:13,650 The key takeaway is that our counter is being updated in serial fashion, but using our imagination, 25 00:02:13,650 --> 00:02:16,890 we're going to say, OK, there are some really long operations in this method. 26 00:02:17,070 --> 00:02:20,760 We need to use multi-threading so that we do not block the main threat. 27 00:02:21,210 --> 00:02:25,530 For now, let's forget about thread pools and all that and just create two thread objects. 28 00:02:25,890 --> 00:02:26,820 So we'll see thread. 29 00:02:28,150 --> 00:02:31,150 The red one is equal to new thread. 30 00:02:32,500 --> 00:02:34,930 That executes a runnable task. 31 00:02:38,220 --> 00:02:46,370 Analysts say Thread Threat two is equal to a new thread once again takes in a renewable task. 32 00:02:47,740 --> 00:02:48,120 But. 33 00:02:52,000 --> 00:02:55,000 All right, then we can say through at one point start. 34 00:02:56,070 --> 00:02:57,270 Threat to Dodge Dart. 35 00:02:59,070 --> 00:03:05,100 And after we make sure that both threads have finished executing their tasks, so by saying thread one 36 00:03:05,100 --> 00:03:10,530 day join and thread to join, only then are we going to print the counter variable. 37 00:03:10,920 --> 00:03:13,530 This needs to be wrapped in a try catch block. 38 00:03:15,780 --> 00:03:21,270 We'll just catch whatever exception comes out of this, it doesn't matter what it is right now. 39 00:03:22,820 --> 00:03:25,640 And we'll print the message. 40 00:03:26,220 --> 00:03:27,620 I'll give you some time to write that out. 41 00:03:34,360 --> 00:03:39,580 You know, if I were to run this code, are you going to get 20000, if only? 42 00:03:42,420 --> 00:03:44,460 Ten thousand seven hundred and sixty four. 43 00:03:44,940 --> 00:03:50,220 You probably got something completely different, depending on how your task scheduler was scheduling 44 00:03:50,220 --> 00:03:50,910 your tasks. 45 00:03:51,090 --> 00:03:55,710 But nonetheless, our code was vulnerable to a race condition. 46 00:03:56,580 --> 00:04:01,170 Remember that a race condition is an incorrect computation that results from many threads trying to 47 00:04:01,170 --> 00:04:02,580 update the same resource. 48 00:04:07,180 --> 00:04:12,580 And your app is vulnerable to race conditions if many threads access or update critical code at the 49 00:04:12,580 --> 00:04:13,150 same time. 50 00:04:19,630 --> 00:04:21,760 How do you identify a critical code? 51 00:04:22,420 --> 00:04:23,440 It's right here. 52 00:04:25,320 --> 00:04:30,930 This line is critical because if two threads executed at the exact same time, you're going to get a 53 00:04:30,930 --> 00:04:34,140 race condition the line counter plus plus. 54 00:04:35,490 --> 00:04:41,700 Remember, if we go back to section two stuff counter plus plus as the same thing as saying counter 55 00:04:42,180 --> 00:04:42,780 +1. 56 00:04:43,560 --> 00:04:43,960 All right. 57 00:04:43,990 --> 00:04:44,850 MS. commented out. 58 00:04:47,610 --> 00:04:49,570 Let's imagine a fully concurrent scenario. 59 00:04:49,590 --> 00:04:50,550 Forget the main thread. 60 00:04:50,710 --> 00:04:54,590 Let's assume the red one and threat to our both being processed by the same core. 61 00:04:55,230 --> 00:04:59,760 The threads run concurrently because we're making progress on two threads at the same time. 62 00:05:00,240 --> 00:05:00,720 Careful. 63 00:05:00,720 --> 00:05:02,730 We're not running two threads at the same time. 64 00:05:02,940 --> 00:05:05,520 We're making progress on two threads at a time. 65 00:05:06,030 --> 00:05:07,710 So first, it'll run this thread. 66 00:05:08,040 --> 00:05:12,840 Let's say it updates the calendar twice and then another thread updates the counter four times. 67 00:05:13,740 --> 00:05:14,700 Now we're at six. 68 00:05:15,060 --> 00:05:20,610 If the execution is fully concurrent, where one core is constantly alternating between two threads, 69 00:05:20,940 --> 00:05:22,530 then we shouldn't have any problems. 70 00:05:26,360 --> 00:05:30,800 But you can never guarantee that because the task scheduler is really random. 71 00:05:31,220 --> 00:05:33,920 What if Threat two is being processed by another court? 72 00:05:34,100 --> 00:05:36,440 In this case, the two threads will run in parallel. 73 00:05:42,480 --> 00:05:46,350 And let's see, the counter is at 2000, imagine both threads. 74 00:05:46,350 --> 00:05:50,340 Read this Part of the code at the exact same time counter is equal to counter. 75 00:05:50,580 --> 00:05:56,070 So they're both going to think, OK, the counter is 2000, and by adding one, it's two thousand and 76 00:05:56,070 --> 00:05:56,370 one. 77 00:05:56,850 --> 00:06:01,500 So the increment operation happened twice, but counter only went up by one. 78 00:06:01,800 --> 00:06:07,410 And that's because two threads happened to access and update the exact same resource at the same time. 79 00:06:07,920 --> 00:06:11,940 This is a race condition, and it's what makes multi-threading extremely unsafe. 80 00:06:16,160 --> 00:06:19,250 And the answer to thread safety is resentment Lux. 81 00:06:20,950 --> 00:06:23,890 Resentment locks can lock critical sections of your code. 82 00:06:24,280 --> 00:06:28,900 They ensure that critical code is accessed in serial fashion, meaning one at a time. 83 00:06:34,410 --> 00:06:39,060 And you can create a lock by creating a new object of the re-enter into the class, which we're going 84 00:06:39,060 --> 00:06:40,890 to do right now, re-enter and lock. 85 00:06:42,280 --> 00:06:42,850 Luck. 86 00:06:43,740 --> 00:06:47,340 Is equal to a new object of the resentment law class. 87 00:06:49,770 --> 00:06:53,460 And we need to look this critical part of our code. 88 00:06:54,030 --> 00:06:56,640 So we're going to pass this lock into our task method. 89 00:06:57,480 --> 00:06:59,370 It's going to receive a RE entrant lock. 90 00:07:10,820 --> 00:07:14,870 We're going to lock this part of our code locked up lock. 91 00:07:15,620 --> 00:07:17,130 We can go ahead and remove these comments. 92 00:07:17,150 --> 00:07:18,350 We don't really need them anymore. 93 00:07:22,240 --> 00:07:27,820 And once one of the threads has finished running this code, then we can unlock it so that the other 94 00:07:27,820 --> 00:07:29,200 thread can then access it. 95 00:07:31,950 --> 00:07:37,410 Ultimately, this is going to make sure that Counter Plus Plus only gets access to one thread at a time, 96 00:07:38,100 --> 00:07:39,760 thus enforcing thread safety. 97 00:07:39,780 --> 00:07:41,040 So if I were in the code. 98 00:07:44,260 --> 00:07:45,220 Everything works. 99 00:07:45,850 --> 00:07:49,720 How exactly is locked up, lock and unlock and forcing thread safety? 100 00:07:50,440 --> 00:07:54,520 Let's take the example where each thread is running on its own core, which means they're going to be 101 00:07:54,520 --> 00:07:56,530 running in parallel once again. 102 00:07:56,530 --> 00:07:58,930 Imagine both threads get to this part of the code. 103 00:07:59,200 --> 00:08:01,360 It's going to lock for one of the threads. 104 00:08:01,360 --> 00:08:04,420 In this case, it's telling thread to hear you at your turn thread. 105 00:08:04,420 --> 00:08:05,500 One does its thing. 106 00:08:08,500 --> 00:08:13,690 And after a thread, one is finished, the code basically unlocks for Thread two, which was patiently 107 00:08:13,690 --> 00:08:14,490 waiting its turn. 108 00:08:14,500 --> 00:08:19,180 Ghosn updates the counter and just like that by locking a critical section of our code. 109 00:08:19,480 --> 00:08:22,540 There is no possibility of there being a race condition. 110 00:08:27,420 --> 00:08:33,690 So to recap, use RE entrant logs to enforce thread safety, your app is vulnerable to race conditions 111 00:08:33,690 --> 00:08:38,280 if many threads are accessing and updating critical code at the same time. 112 00:08:42,100 --> 00:08:46,180 Use locks to ensure that critical sections of your code are running in serial.