diff --git a/ch16/extensible-concurrency/Cargo.lock b/ch16/extensible-concurrency/Cargo.lock
new file mode 100644
index 0000000..453748d
--- /dev/null
+++ b/ch16/extensible-concurrency/Cargo.lock
@@ -0,0 +1,7 @@
+# This file is automatically @generated by Cargo.
+# It is not intended for manual editing.
+version = 3
+
+[[package]]
+name = "extensible-concurrency"
+version = "0.1.0"
diff --git a/ch16/extensible-concurrency/Cargo.toml b/ch16/extensible-concurrency/Cargo.toml
new file mode 100644
index 0000000..fcde9e3
--- /dev/null
+++ b/ch16/extensible-concurrency/Cargo.toml
@@ -0,0 +1,6 @@
+[package]
+name = "extensible-concurrency"
+version = "0.1.0"
+edition = "2021"
+
+[dependencies]
diff --git a/ch16/extensible-concurrency/src/main.rs b/ch16/extensible-concurrency/src/main.rs
new file mode 100644
index 0000000..c22ec40
--- /dev/null
+++ b/ch16/extensible-concurrency/src/main.rs
@@ -0,0 +1,20 @@
+//! # Extensible Concurrency with the `Sync` and `Send` Traits
+//!
+//! Two concurrency concepts embedded in the language: the std::marker
+//! `Sync` and `Send`.
+
+fn main() {
+    // Allowing Transference of ownership between threads with `Send`
+    //
+    // `Send` marker traits indicates ownership of values of the
+    // type implementing `Send` can be transferred between threads.
+    // Almost every Rust type is `Send` besides `Rc<T>`.
+
+    // Allowing Access from Multiple Threads with `Sync`
+    //
+    // The `Sync` marker trait indicates it's safe for the type implementing
+    // `Sync` to be referenced from multiple threads.
+    //
+    // Implementing Send and Sync Manually Is Unsafe
+    // This doesn't exactly explain why, just says look at Chapter 20.
+}
diff --git a/ch16/message-passing/Cargo.lock b/ch16/message-passing/Cargo.lock
new file mode 100644
index 0000000..0a53e8a
--- /dev/null
+++ b/ch16/message-passing/Cargo.lock
@@ -0,0 +1,7 @@
+# This file is automatically @generated by Cargo.
+# It is not intended for manual editing.
+version = 3
+
+[[package]]
+name = "message-passing"
+version = "0.1.0"
diff --git a/ch16/message-passing/Cargo.toml b/ch16/message-passing/Cargo.toml
new file mode 100644
index 0000000..24bd2ee
--- /dev/null
+++ b/ch16/message-passing/Cargo.toml
@@ -0,0 +1,6 @@
+[package]
+name = "message-passing"
+version = "0.1.0"
+edition = "2021"
+
+[dependencies]
diff --git a/ch16/message-passing/src/main.rs b/ch16/message-passing/src/main.rs
new file mode 100644
index 0000000..4c04e41
--- /dev/null
+++ b/ch16/message-passing/src/main.rs
@@ -0,0 +1,100 @@
+//! One way to ensure safe concurrency is message passing.
+//! Threads send data between one another.
+//! To accomplish message-sending concurrency, Rust
+//! provides an implementation of channels. Channel
+//! is generally a way for data to sent from one
+//! channel to another.
+//!
+//! A channel has two halves: a transmitter and a reciever.
+//! Channel is *closed* if either the transmitter or
+//! reciever is dropped.
+
+use std::sync::mpsc;
+use std::thread;
+use std::time::Duration;
+
+fn main() {
+    // mpsc stands for multiple producer, single consumer.
+    // Rust can have multilple sending and only one receiving
+    // tx for transmitter and rx for receiver.
+    let (tx, rx) = mpsc::channel();
+
+    // spawned thread needs to own transmitter to send messages.
+    thread::spawn(move || {
+        let val = String::from("hi");
+        tx.send(val).unwrap();
+        // Can't use after `send` call because the receiving
+        // thread may modify the value.
+        // println!("val is {val}");
+    });
+
+    // receiver has two useful methods: `recv` and `try_recv`.
+    // `recv` will block main thread's execution.
+    // `try_recv` useful if this thread has other work to do
+    // while waiting for messages.
+    let received = rx.recv().unwrap();
+    println!("Got: {received}");
+
+    // Sending multiple values and seeing the reciever waiting
+
+    println!("Sending multiple values and seeing the receiver waiting section");
+
+    let (tx, rx) = mpsc::channel();
+
+    thread::spawn(move || {
+        let vals = vec![
+            String::from("hi"),
+            String::from("from"),
+            String::from("the"),
+            String::from("thread"),
+        ];
+
+        for val in vals {
+            tx.send(val).unwrap();
+            thread::sleep(Duration::from_secs(1));
+        }
+    });
+
+    for received in rx {
+        println!("Got: {received}");
+    }
+
+    // Creating multiple producers by cloning the transmitter
+
+    println!("Creating multiple producers by cloning the transmitter");
+
+    let (tx, rx) = mpsc::channel();
+
+    let tx1 = tx.clone();
+    thread::spawn(move || {
+        let vals = vec![
+            String::from("hi"),
+            String::from("from"),
+            String::from("the"),
+            String::from("thread"),
+        ];
+
+        for val in vals {
+            tx1.send(val).unwrap();
+            thread::sleep(Duration::from_secs(1));
+        }
+    });
+
+    thread::spawn(move || {
+        let vals = vec![
+            String::from("more"),
+            String::from("messages"),
+            String::from("for"),
+            String::from("you"),
+        ];
+
+        for val in vals {
+            tx.send(val).unwrap();
+            thread::sleep(Duration::from_secs(1));
+        }
+    });
+
+    for received in rx {
+        println!("Got: {received}");
+    }
+}
diff --git a/ch16/shared-state/Cargo.lock b/ch16/shared-state/Cargo.lock
new file mode 100644
index 0000000..0eaa599
--- /dev/null
+++ b/ch16/shared-state/Cargo.lock
@@ -0,0 +1,7 @@
+# This file is automatically @generated by Cargo.
+# It is not intended for manual editing.
+version = 3
+
+[[package]]
+name = "shared-state"
+version = "0.1.0"
diff --git a/ch16/shared-state/Cargo.toml b/ch16/shared-state/Cargo.toml
new file mode 100644
index 0000000..da297ea
--- /dev/null
+++ b/ch16/shared-state/Cargo.toml
@@ -0,0 +1,6 @@
+[package]
+name = "shared-state"
+version = "0.1.0"
+edition = "2021"
+
+[dependencies]
diff --git a/ch16/shared-state/src/main.rs b/ch16/shared-state/src/main.rs
new file mode 100644
index 0000000..457a82a
--- /dev/null
+++ b/ch16/shared-state/src/main.rs
@@ -0,0 +1,101 @@
+//! # Shared-State Concurrency
+//!
+//! This is another way to handle concurrency. Sharing data.
+//! Consider the slogan: "do not communicate by sharing memory."
+
+use std::rc::Rc;
+use std::sync::{Arc, Mutex};
+use std::thread;
+
+fn main() {
+    // Using mutexes to allow access to data from one thread at a time
+    //
+    // Mutex is an abbreviation for mutual exclusion. Allows only one
+    // thread to access some data at any given time.
+    // To access data in a mutex, thread must first signal it wants
+    // access by asking to acquire the mutex's lock. The lock is
+    // a data structure part of the mutex that keeps track of who
+    // currently has exclusive access to the data. Therefore,
+    // mutex described as guarding the data.
+    //
+    // Mutexes have two rules:
+    // 1) Must attempt to acquire the lock before using the data
+    // 2) When done with data that mutex guards, must unlock data
+    //    so other threads can acquire lock.
+
+    let m = Mutex::new(5);
+
+    {
+        let mut num = m.lock().unwrap();
+        *num = 6;
+    }
+
+    println!("m = {m:?}");
+
+    // Sharing a Mutex<T> Between multiple threads
+
+    // let counter = Mutex::new(0);
+    // let mut handles = vec![];
+
+    // for _ in 0..10 {
+    //     let handle = thread::spawn(move || {
+    //         let mut num = counter.lock().unwrap();
+
+    //         *num += 1;
+    //     });
+    //     handles.push(handle);
+    // }
+
+    // for handle in handles {
+    //     handle.join().unwrap();
+    // }
+
+    // println!("Result: {}", *counter.lock().unwrap());
+
+    // Multiple ownership with multiple threads
+
+    // let counter = Rc::new(Mutex::new(0));
+    // let mut handles = vec![];
+
+    // for _ in 0..10 {
+    //     let counter = Rc::clone(&counter);
+    //     let handle = thread::spawn(move || {
+    //         let mut num = counter.lock().unwrap();
+
+    //         *num += 1;
+    //     });
+    //     handles.push(handle);
+    // }
+
+    // for handle in handles {
+    //     handle.join().unwrap();
+    // }
+
+    // println!("Result: {}", *counter.lock().unwrap());
+
+    // Atomic reference counting with Arc<T>
+    //
+    // Arc<T> is like Rc<T> is safe to use concurrent situations.
+    // The a stands for atomic meanings it's an atomically reference
+    // counted type. Thread safety like this comes at an example.
+    // Arc<T> and Rc<T> have the same API.
+
+    let counter = Arc::new(Mutex::new(0));
+    let mut handles = vec![];
+
+    for _ in 0..10 {
+        let counter = Arc::clone(&counter);
+        let handle = thread::spawn(move || {
+            let mut num = counter.lock().unwrap();
+
+            *num += 1;
+        });
+        handles.push(handle);
+    }
+
+    for handle in handles {
+        handle.join().unwrap();
+    }
+
+    println!("Result: {}", *counter.lock().unwrap());
+}
diff --git a/ch16/threads/Cargo.lock b/ch16/threads/Cargo.lock
new file mode 100644
index 0000000..e412e95
--- /dev/null
+++ b/ch16/threads/Cargo.lock
@@ -0,0 +1,7 @@
+# This file is automatically @generated by Cargo.
+# It is not intended for manual editing.
+version = 3
+
+[[package]]
+name = "threads"
+version = "0.1.0"
diff --git a/ch16/threads/Cargo.toml b/ch16/threads/Cargo.toml
new file mode 100644
index 0000000..bd4edf7
--- /dev/null
+++ b/ch16/threads/Cargo.toml
@@ -0,0 +1,6 @@
+[package]
+name = "threads"
+version = "0.1.0"
+edition = "2021"
+
+[dependencies]
diff --git a/ch16/threads/src/main.rs b/ch16/threads/src/main.rs
new file mode 100644
index 0000000..113b20a
--- /dev/null
+++ b/ch16/threads/src/main.rs
@@ -0,0 +1,38 @@
+use std::thread;
+use std::time::Duration;
+
+fn main() {
+    let handle = thread::spawn(|| {
+        for i in 1..10 {
+            println!("hi number {i} from the spawned thread!");
+            thread::sleep(Duration::from_millis(1));
+        }
+    });
+
+    for i in 1..5 {
+        println!("hi number {i} from the main thread!");
+        thread::sleep(Duration::from_millis(1));
+    }
+
+    // Waiting for all threads to finish using join handles
+    // Without the join below, threads stop prematurely
+    // because there is no guarantee on the order in which
+    // threads run, also can't guarantee spawned thread
+    // will get to run at all.
+
+    // calling `join` on a handle blocks the thread currently
+    // running until the thread represented by `handle`
+    // terminates.
+    handle.join().unwrap();
+
+    // Using move closures with threads
+    //
+    // Often use move keyword with closures because
+    // closure takes ownership fo values it uses from environment.
+
+    let v = vec![1, 2, 3];
+    let handle = thread::spawn(move || {
+        println!("Here's a vector: {v:?}");
+    });
+    handle.join().unwrap();
+}