diff --git a/README.md b/README.md
index 50f93864af236cf41e193db8e987d44e80c215ca..ae74a2c23476b69b513776f51e0035946b0d86fc 100644
--- a/README.md
+++ b/README.md
@@ -49,6 +49,10 @@ You should watch the prerecorded lectures before doing the exercies.
 | 5    | 2022.03.23 | Concurrency 1    | Live                   | None                    | Lab 4 & 5          |
 | 6    | 2022.03.30 | Concurrency 2    | Live                   | None                    | Lab 5 & 6          |
 | 7    | 2022.04.06 | Concurrency 3    | Live                   | None                    | Lab 6              |
+| 8    | 2022.04.13 | Concurrency 4    | Live                   | None                    | Lab 6 & 7          |
+| 9    | 2022.04.20 | Easter Break     | None                   | None                    | None               |
+| 10   | 2022.04.27 | Midterm Exam     | Midterm Exam           | None                    | Lab 7              |
+
 
 Solutions to the exercises are released after each deadline. We do not provide solutions for the labs.
 
@@ -107,6 +111,7 @@ Labs are submitted by pushing your code on GitLab, see details in the [grading a
 | Lab 4 | Barnes-Hut Simulation      | 2022.03.16  | 2022.03.27  |
 | Lab 5 | Concurrent Bounded Buffer  | 2022.03.23  | 2022.04.03  |
 | Lab 6 | Lock-free sorted list      | 2022.03.30  | 2022.04.10  |
+| Lab 7 | Hazard Pointer             | 2022.04.13  | 2022.05.01  |
 
 # Exercises
 
diff --git a/labs/lab7-hazard-pointer/hazardptr.md b/labs/lab7-hazard-pointer/hazardptr.md
new file mode 100644
index 0000000000000000000000000000000000000000..4554466c5ba713ec063d5ee64dc0cc2c88f41ffe
--- /dev/null
+++ b/labs/lab7-hazard-pointer/hazardptr.md
@@ -0,0 +1,141 @@
+# Sorted Doubly Linked-List 
+
+The goal of this assignment is to implement a concurrent list that stores values of type `Int` in ascending order. Last week, we have seen lock-free list which uses Node marking to marks nodes to be deleted. The week, the list is a doubly linked list without any node marking. The data structure allows access to a single writer(Insert/Delete) but multiple readers can run concurrently. 
+
+The goal will be to have a data structure that can safely allow readers to do the traversal even if writer has deleted the node. Hazard pointers will be used to achieve that.
+
+## Hazard Pointer (https://ieeexplore.ieee.org/document/1291819)
+
+Hazard Pointer is a garbage collection technique which allows concurrent access to an object in a thread even when it might be deleted by other threads. For example, thread A might be deleting a node and at the same time another thread B can have access to that same node. If thread A frees the memory, then thread B will crash because it is trying to access invalid address. 
+
+The sorted list methods you will implement will make use of hazard pointers. Hazard pointers are a per-thread pointers which are used to protect readers in case there is a concurrent delete of the same node. For the sorted list data structure, you will use two hazard pointers per thread. 
+
+Whenever there is a delete operation, the node is added to the per-thread retireList. If the size of the retireList exceeds some threshold, then that thread will iterate over all per-thread hazard pointers to figure out which nodes are currently not in use and can be safely deleted. 
+
+Following is the implementation of the AbstractHazardPointer class.
+
+```scala
+abstract class AbstractHazardPointer(numPointerPerThread: Int) extends Monitor:
+
+  val maxThreads = 10
+
+  val threshold = 2
+
+  val hazardPointerArray: ArrayBuffer[Option[Node]] = ArrayBuffer.fill(numPointerPerThread * maxThreads)(None)
+
+  val retiredListArray: ArrayBuffer[ArrayBuffer[Node]] = ArrayBuffer.fill(maxThreads)(ArrayBuffer())
+
+  // This function will be overridden when running in parallel.
+  def getMyId(): Int = 0
+
+  // Update ith per-thread hazard pointer ( 0 <= i <= numPointerPerThread )
+  def update(i: Int, n: Option[Node]): Unit
+
+  // Return ith per-thread hazard pointer ( 0 <= i <= numPointerPerThread )
+  def get(i: Int): Option[Node]
+
+  def retireNode(node: Node) : Unit
+```
+
+hazardPointerArray is an Array of hazard pointers. This array will store per-thread hazard pointers. You can use `get` / `update` functions to read/write per-thread hazard pointers.
+
+You have to implement the retireNode function in the hazardPointer class.
+
+```scala
+class HazardPointer(numPointerPerThread: Int) extends AbstractHazardPointer(numPointerPerThread):
+
+  def retireNode(node: Node) = ???
+```
+### `retireNode`
+
+Implement the function to retire the node. The method should do the following :
+- Add the node to thread's retired list.
+- If the size of retired list is greater than a pre-defined threshold. Remove all the elements from the list which are not pointed by any hazard pointer of all the threads.
+
+## The Sorted List Data Structure
+
+The data structure you will implement is a mutable linked list of integers, sorted in ascending order. Each integer is stored in a `Node`. In addition to the integer value, each node contains a mutable reference to the next and previous node in the list.
+
+```scala
+class Node(val value: Int, var next: Option[Node] = null, var prev: Option[Node] = null) {
+}
+```
+
+Then, `SortedList` is simply a class that holds a reference to the first node of the list. This class is defined in `SortedList.scala`.
+
+```scala
+class SortedList extends AbstractSortedList:
+  
+
+  // The sentinel node at the head.
+  val _head: Option[Node] = Option(createNode(0, None, None, isHead = true))
+
+  // The first logical node is referenced by the head.
+  def firstNode: Option[Node] = _head.get.next
+
+  val hazardPointers = new HazardPointer(2)
+
+  // Finds the first node whose value satisfies the predicate.
+  // Returns the predecessor of the node and the node.
+  def findNodeWithPrev(pred: Int => Boolean): (Option[Node], Option[Node]) = ???
+
+  //Find Nth Node after current element. Return 0 if out of bounds.
+  def getNthNext(e: Int, n: Int): Int = ???
+
+  // Count occurrence of the element.
+  def countOccurrences(e: Int): Int = ???
+
+  // Insert an element in the list.
+  def insert(e: Int): Unit = synchronized {
+    ???
+    }
+
+  // Checks if the list contains an element.
+  def contains(e: Int): Boolean = ???
+
+  // Delete an element from the list.
+  // Should only delete one element when multiple occurrences are present.
+  def delete(e: Int): Boolean = synchronized {
+    ???
+    }
+
+
+```
+
+The value `_head` of the list is called a [*sentinel* node](https://en.wikipedia.org/wiki/Sentinel_node). This value is simply `Node` that will serve only as a reference to the first actual node of the list. The value (viz. zero) held by this special node should be completely ignored. 
+
+The data structure support single writer and multiple readers. Insert and Delete function acts as writing to the data structure and these should be executed one at a time, even though multiple threads are trying to insert/delete. Rest of the functions are reading the data structure and can be executed concurrently. Use hazard pointers in these function to protect against concurrent delete.
+
+### `findNodeWithPrev`
+
+The first method you will implement is an internal helper method which will be used all other methods.
+This method should do a traversal of the list to find the first node whose value satisfies the parameter predicate.
+The method should return the following two values as a pair:
+- the predecessor of the node,
+- the node.
+
+If `node` is the first node whose value satisfies the predicate and `predecessor` its predecessor, then the method should return `(predecessor, Some(node))`. Due to the use of the sentinel node at the head of the list, the method is bound to find a predecessor, even for the first logical node. There can also be concurrent insert/delete while traversal, so the method should also check if the next of the `predecessor` node points to `node` or not. If yes, then the method should return `(predecessor, Some(node))` or else start from the beginning.
+
+When the predicate doesn't hold on any of the values, then the function should return `(last, None)`, where
+`last` is the last node of the list.
+
+Since the traveral is lock-free, the previous and current node should be protected by hazard pointers.
+
+### `insert` / `delete`
+
+Implement insert and delete into doubly linked list. You can use `findNodeWithPrev` function.
+
+### `contains`
+
+Next, you should implement the `contains` method, which checks if the list contains a given element. 
+
+### `getNthNext`
+
+Implement a method which will find the first occurence of `e` and then return the value of the node which is Nth next from that node. For example, if we have a list 1->2->3->4->5, element to search(e) = 3 and N=2. Then Nth next is 5.
+
+### `countOccurrences`
+
+Finally, implement a method which count occurences of the element in the list.
+
+You are now done with this assignment. Congratulations!
+
diff --git a/slides/week8-concurrency-4.pdf b/slides/week8-concurrency-4.pdf
new file mode 100644
index 0000000000000000000000000000000000000000..8129a23f42fb7e223a2920fddf5284ed3aeb882b
Binary files /dev/null and b/slides/week8-concurrency-4.pdf differ