MS Lesson26: Threads
1. Process - emeliyyat sistemi terefinden ishe salinan, oz ayrica yaddash sahesine malik olan programin icra nusxesidir.
Mes biz kompumuzda muxtelif programlar acanda Paint, Excel ve s. bunlar ferqli proseslerdir.
OS her bir prosese ferqli registerler, stack memory, heap memory assign edir.
Restoran misali:
Restoran = process
Bina = yaddash (RAM)
Ishciler = thread
Yeni process ishe salinmish bir programdir.
* Her proses oz yaddashinda ishleyir, bashqasina toxuna bilmez.
* OS her prosese unikal ID verir.
* Yaratmaq / silmek bahalidir.
* Biri crash olsa, digerine tesir etmir.
Bir prosesin icinde coxlu thread ola biler. Amma bir thread yalniz bir prosese aid ola biler.
Java kodu bashlayanda JVM ozu de bir nece thread yaradir:
* main thread - bizim kodumuz
* GC thread - Garbage Collector
* Finalizer thread
* Signal Dispatcher thread
2. Thread - process icinde ishleyen ayrica ish axinidir. Kodun setir setir icra olundugu yoldur.
Restoran - process
Ashpaz 1 - pizza bishirir - thread1
Ashpaz 2 - salat hazirlayir - thread2
Ashpaz 3 - desert duzeldir - thread3
Hami eyni anda ishleyir - paralel.
Hami eyni metbexte ishelyir - eyni yaddash.
3. Time Slicing
CPU - tekce beyin deyil, milyardlarla tranzistordan ibaret cipdir. Tranzistor elektrik kecirik ya kecirmir 0 ve 1.
Core - CPU-nun icinde musteqil bir ishcidir. Ona kod verirsen o da icra edir, bashqa hecne bilmir.
CPU - fabrika, Core - fabrikadaki ishci.
Core-un icinde 4 esas sahe var:
1. Fetch unit: "Novbeti emri getir"
RAM-da bizim Java kodumuz durur:
Unvan 100: int a = 5;
Unvan 104: int b = 3;
Unvan 108: int c = a + b;
Fetch unit:
"Unvan 100 get -> Decode ver"
"Unvan 104 get -> Decode var"
...
Problemi: RAM yavashdir, 70 nanosaniye gozlemek lazimdir, Core ise 0.3 nanosaniyede ishleyir. Yeni Core RAM-dan 200x daha suretlidir. Buna gore Core-un daxilinde oz cache-i var.
2. Decode unit: "Bu emr ne demekdir?"
Tercumeci, genen emri CPU diline cevirir.
Sən yazırsan:
int c = a + b;
JVM çevirir (Bytecode):
iload_1 ← a-nı yüklə
iload_2 ← b-ni yüklə
iadd ← topla
istore_3 ← c-yə yaz
CPU görür (Machine Code):
10110000 00000101
10110011 00000011
00000001 11000011
Decode unit bunlari oxuyur ve deyir:
"A-nı Register-ə yüklə"
"B-ni Register-ə yüklə"
"İkisini ALU-da topla"
"Nəticəni Register-ə yaz"
3. ALU: "Hesablama et"
Arithmetic Logic Unit - butun hesablama burada gedir.
4. Register: "Neticeni saxla"
Yaddaş növləri sürətə görə:
Register │██████████████████████│ 0.3 ns ← Core-un içi
L1 Cache │████████████████ │ 1 ns
L2 Cache │████████ │ 5 ns
L3 Cache │████ │ 15 ns
RAM │█ │ 70 ns ← 200x yavaş!
SSD │ │ 100 µs
HDD │ │ 10 ms
Core-da cəmi ~16 Register var Hər biri 64 bit = 8 byte saxlayır
Bir core eyni anda yalniz 1 ish gore biler. Amma ele suretli novbe ile kecir ki, sanki hamisini eyni anda icra edir.
package az.etibarli;
class Runner1 {
public void execute() {
for (int i = 0; i < 10; i++) {
System.out.println("Runner1: " + i);
}
}
}
class Runner2 {
public void execute() {
for (int i = 0; i < 10; i++) {
System.out.println("Runner2: " + i);
}
}
}
public class Main {
static void main() {
Runner1 runner1 = new Runner1();
Runner2 runner2 = new Runner2();
runner1.execute();
runner2.execute();
}
}
package az.etibarli;
class Runner1 implements Runnable {
@Override
public void run() {
for (int i = 0; i < 10; i++) {
System.out.println("Runner1: " + i);
}
}
}
class Runner2 implements Runnable {
@Override
public void run() {
for (int i = 0; i < 10; i++) {
System.out.println("Runner2: " + i);
}
}
}
public class Main {
static void main() {
Thread thread1 = new Thread(new Runner1());
Thread thread2 = new Thread(new Runner2());
thread1.start();
thread2.start();
}
}
package az.etibarli;
class Runner1 implements Runnable {
@Override
public void run() {
for (int i = 0; i < 10; i++) {
System.out.println("Runner1: " + i);
}
}
}
class Runner2 implements Runnable {
@Override
public void run() {
for (int i = 0; i < 10; i++) {
System.out.println("Runner2: " + i);
}
}
}
public class Main {
static void main() throws InterruptedException {
System.out.println("Start");
Thread thread1 = new Thread(new Runner1());
Thread thread2 = new Thread(new Runner2());
thread1.start();
thread2.start();
thread1.join();
System.out.println("Finish");
}
}
package az.etibarli;
class Runner1 implements Runnable {
@Override
public void run() {
for (int i = 0; i < 10; i++) {
System.out.println("Runner1: " + i);
}
}
}
class Runner2 implements Runnable {
@Override
public void run() {
for (int i = 0; i < 10; i++) {
try {
Thread.sleep(1000);
} catch (Exception e) {
e.printStackTrace();
}
System.out.println("Runner2: " + i);
}
}
}
public class Main {
static void main() throws InterruptedException {
System.out.println("Start");
Thread thread1 = new Thread(new Runner1());
Thread thread2 = new Thread(new Runner2());
thread1.start();
thread2.start();
thread1.join();
System.out.println("Finish");
}
}
package az.etibarli;
public class Main {
static long heavyWork() {
long result = 0;
for (long i = 0; i < 1_000_000_000L; i++) {
result += i;
}
return result;
}
static void main() throws InterruptedException {
System.out.println("=== 1 Thread ===");
long start1 = System.currentTimeMillis();
heavyWork();
heavyWork();
long end1 = System.currentTimeMillis();
System.out.println("1 Thread time: " +
(end1 - start1) + "ms");
System.out.println("\n=== 2 Thread ===");
long start2 = System.currentTimeMillis();
Thread t1 = new Thread(() -> heavyWork());
Thread t2 = new Thread(() -> heavyWork());
t1.start();
t2.start();
t1.join();
t2.join();
long end2 = System.currentTimeMillis();
System.out.println("2 Thread time: " +
(end2 - start2) + "ms");
}
}
package az.etibarli;
class Runner1 implements Runnable {
@Override
public void run() {
for (int i = 0; i < 10; i++) {
System.out.println("Runner1: " + i);
}
}
}
class Runner2 implements Runnable {
@Override
public void run() {
for (int i = 0; i < 10; i++) {
try {
Thread.sleep(1000);
} catch (Exception e) {
e.printStackTrace();
}
System.out.println("Runner2: " + i);
}
}
}
public class Main {
static void main() throws InterruptedException {
System.out.println("Start");
Thread thread1 = new Thread(new Runner1());
Thread thread2 = new Thread(new Runner2());
thread1.start();
thread2.start();
// list of threads in JVM
for (Thread t : Thread.getAllStackTraces().keySet()) {
System.out.println("Thread name: " + t.getName() + ", State: " + t.getState());
}
thread1.join();
System.out.println("Finish");
}
}
package az.etibarli;
class NormalWorker implements Runnable {
public void run() {
try {
Thread.sleep(1000);
} catch (Exception e) {
e.printStackTrace();
}
System.out.println("Executing the normal thread...");
}
}
class DaemonWorker implements Runnable {
public void run() {
while (true) {
try {
Thread.sleep(100);
} catch (Exception e) {
e.printStackTrace();
}
System.out.println("Executing the daemon thread...");
}
}
}
public class Main {
static void main() throws InterruptedException {
System.out.println("Started...");
Thread t1 = new Thread(new NormalWorker());
Thread t2 = new Thread(new DaemonWorker());
t2.setDaemon(true);
t1.start();
t2.start();
System.out.println("Finished...");
}
}
* Daemon Thread - background thread support user thread. JVM does not wait for daemon threads. Must explicitly set using setDaemon(true). Can also have any priority, but usually lower. Acts as background service threads.
package az.etibarli;
class Task implements Runnable {
public void run() {
for (int i = 0; i < 5; i++) {
System.out.println(Thread.currentThread().getName() + " count: " + i);
try {
Thread.sleep(100);
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
public class Main {
static void main() throws InterruptedException {
System.out.println("Started...");
Thread low = new Thread(new Task(), "Low priority thread");
Thread medium = new Thread(new Task(), "Medium priority thread");
Thread high = new Thread(new Task(), "High priority thread");
low.setPriority(Thread.MIN_PRIORITY);
medium.setPriority(Thread.NORM_PRIORITY);
high.setPriority(Thread.MAX_PRIORITY);
low.start();
medium.start();
high.start();
System.out.println("Finished...");
}
}
package az.etibarli;
public class SynchronizationExample {
private static int counter = 0;
public static void increment() {
counter++;
}
static void main() throws InterruptedException {
Thread t1 = new Thread(() -> {
for (int i = 0; i < 10000; i++) {
increment();
}
});
Thread t2 = new Thread(() -> {
for (int i = 0; i < 10000; i++) {
increment();
}
});
t1.start();
t2.start();
t1.join();
t2.join();
System.out.println("Counter value is : " + counter);
}
}
package az.etibarli;
public class SynchronizationExample {
private static int counter = 0;
public synchronized static void increment() {
counter++;
}
static void main() throws InterruptedException {
Thread t1 = new Thread(() -> {
for (int i = 0; i < 10000; i++) {
increment();
}
});
Thread t2 = new Thread(() -> {
for (int i = 0; i < 10000; i++) {
increment();
}
});
t1.start();
t2.start();
t1.join();
t2.join();
System.out.println("Counter value is : " + counter);
}
}
package az.etibarli;
public class SynchronizationExample {
private static int counter1 = 0;
private static int counter2 = 0;
public synchronized static void increment1() {
try {
Thread.sleep(1);
} catch (Exception e) {
e.printStackTrace();
}
counter1++;
}
public synchronized static void increment2() {
try {
Thread.sleep(1);
} catch (Exception e) {
e.printStackTrace();
}
counter2++;
}
static void main() throws InterruptedException {
long start = System.currentTimeMillis();
Thread t1 = new Thread(() -> {
for (int i = 0; i < 10000; i++) {
increment1();
}
});
Thread t2 = new Thread(() -> {
for (int i = 0; i < 10000; i++) {
increment2();
}
});
t1.start();
t2.start();
t1.join();
t2.join();
long end = System.currentTimeMillis();
System.out.println("Counter value is : " + counter1);
System.out.println("Counter value is : " + counter2);
System.out.println("Time elapsed: " + (end - start));
}
}
package az.etibarli;
public class SynchronizationExample {
private static int counter1 = 0;
private static int counter2 = 0;
private static final Object lock1 = new Object();
private static final Object lock2 = new Object();
public synchronized static void increment1() {
// t1, t2
// synchronized (lock1) {
try {
Thread.sleep(3000);
} catch (Exception e) {
e.printStackTrace();
}
counter1++;
// }
// synchronized (lock2) {
try {
Thread.sleep(2000);
} catch (Exception e) {
e.printStackTrace();
}
counter2++;
// }
}
static void main() throws InterruptedException {
long start = System.currentTimeMillis();
Thread t1 = new Thread(() -> {
// for (int i = 0; i < 5000; i++) {
increment1();
// }
});
Thread t2 = new Thread(() -> {
// for (int i = 0; i < 5000; i++) {
increment1();
// }
});
t1.start();
t2.start();
t1.join();
t2.join();
long end = System.currentTimeMillis();
System.out.println("Counter value is : " + counter1);
System.out.println("Counter value is : " + counter2);
System.out.println("Time elapsed: " + (end - start));
}
}
package az.etibarli;
class ObjectLocking {
public synchronized void instanceMethod() {
System.out.println(Thread.currentThread().getName() + " started instance method...");
try {
Thread.sleep(2000);
} catch (Exception e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + " finished instance method...");
}
}
public class Main {
static void main() throws InterruptedException {
long start = System.currentTimeMillis();
ObjectLocking obj1 = new ObjectLocking();
ObjectLocking obj2 = new ObjectLocking();
Runnable task1 = obj1::instanceMethod;
Runnable task2 = obj1::instanceMethod;
Thread t1 = new Thread(task1, "First Thread");
Thread t2 = new Thread(task2, "Second Thread");
t1.start();
t2.start();
t1.join();
t2.join();
long end = System.currentTimeMillis();
System.out.println("Time elapsed: " + (end - start));
}
}
package az.etibarli;
class ObjectLocking {
public static synchronized void instanceMethod() {
System.out.println(Thread.currentThread().getName() + " started instance method...");
try {
Thread.sleep(2000);
} catch (Exception e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + " finished instance method...");
}
}
public class Main {
static void main() throws InterruptedException {
long start = System.currentTimeMillis();
Runnable task1 = ObjectLocking::instanceMethod;
Runnable task2 = ObjectLocking::instanceMethod;
Thread t1 = new Thread(task1, "First Thread");
Thread t2 = new Thread(task2, "Second Thread");
t1.start();
t2.start();
t1.join();
t2.join();
long end = System.currentTimeMillis();
System.out.println("Time elapsed: " + (end - start));
}
}
package az.etibarli;
class Process {
public void produce() throws Exception {
synchronized (this) {
System.out.println("Running the produce method...");
wait();
System.out.println("Again in the produce method...");
}
}
public void consume() throws Exception {
Thread.sleep(4000);
synchronized (this) {
System.out.println("Running the consume method...");
notify();
System.out.println("After the notify() method call in the consume method...");
}
}
}
public class Main {
static void main() throws InterruptedException {
long start = System.currentTimeMillis();
Process process = new Process();
Thread t1 = new Thread(() -> {
try {
process.produce();
} catch (Exception e) {
e.printStackTrace();
}
});
Thread t2 = new Thread(() -> {
try {
process.consume();
} catch (Exception e) {
e.printStackTrace();
}
});
t1.start();
t2.start();
long end = System.currentTimeMillis();
// System.out.println("Time elapsed: " + (end - start));
}
}
Let's discuss the difference between sleep and wait. They may seem to be very similar but there are fundamental differences between them.
you call
waiton the Object while on the other hand you callsleepon the Thread itselfwait can be interrupter (this is why we need the InterruptedException) while on the other hand sleep can not
wait(andnotify) must happen in asynchronizedblock on the monitor object whereassleepdoes notsleepoperation does not release the locks it holds while on the other handwaitreleases the lock on the object thatwait()is called on
package az.etibarli;
import java.util.LinkedList;
import java.util.List;
class SharedBuffer {
private List<Integer> buffer = new LinkedList<>();
private int capacity = 5;
public synchronized void produce() throws Exception {
if (buffer.size() == capacity) {
System.out.println("Buffer is full, produce waiting...");
wait();
}
System.out.println("Adding items with the producer...");
for (int i = 0; i < capacity; i++) {
buffer.add(i);
System.out.println("Added value: " + i);
}
// wake up the consumer
notify();
}
public synchronized void consume() throws Exception {
if (buffer.size() < capacity) {
System.out.println("Buffer not fully yet, consumer waiting...");
wait();
}
while (!buffer.isEmpty()) {
int item = buffer.remove(0);
System.out.println("Consumer removes: " + item);
Thread.sleep(300);
}
// wake up the producer
notify();
}
}
class Consumer implements Runnable {
private SharedBuffer sharedBuffer;
public Consumer(SharedBuffer sharedBuffer) {
this.sharedBuffer = sharedBuffer;
}
@Override
public void run() {
while (true) {
try {
this.sharedBuffer.consume();
Thread.sleep(500);
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
class Producer implements Runnable {
private SharedBuffer sharedBuffer;
public Producer(SharedBuffer sharedBuffer) {
this.sharedBuffer = sharedBuffer;
}
@Override
public void run() {
while (true) {
try {
this.sharedBuffer.produce();
Thread.sleep(500);
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
public class Main {
static void main() throws InterruptedException {
SharedBuffer buffer = new SharedBuffer();
Thread t1 = new Thread(new Producer(buffer));
Thread t2 = new Thread(new Consumer(buffer));
t1.start();
t2.start();
}
}
package az.etibarli;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
public class DeadLock {
private Lock lock1 = new ReentrantLock(true);
private Lock lock2 = new ReentrantLock(true);
static void main() {
DeadLock deadLock = new DeadLock();
new Thread(deadLock::worker1, "worker1").start();
new Thread(deadLock::worker2, "worker2").start();
}
public void worker1() {
lock1.lock();
System.out.println("Worker 1 acquires the lock1...");
try {
Thread.sleep(300);
} catch (InterruptedException e) {
e.printStackTrace();
}
lock2.lock();
System.out.println("Worker 1 acquires the lock2...");
lock1.unlock();
lock2.unlock();
}
public void worker2() {
lock2.lock();
System.out.println("Worker 2 acquires the lock2...");
try {
Thread.sleep(300);
} catch (InterruptedException e) {
e.printStackTrace();
}
lock1.lock();
System.out.println("Worker 2 acquires the lock1...");
lock2.unlock();
lock1.unlock();
}
}
package az.etibarli;
public class WithoutVolatile {
// volatile YOX!
private static boolean running = true;
public static void main(String[] args) throws Exception {
Thread worker = new Thread(() -> {
int count = 0;
while (running) { // ← running-i Cache-dən oxuyur!
count++;
}
System.out.println("Worker dayandı! Count: " + count);
});
worker.start();
Thread.sleep(2000); // 2 saniyə gözlə
System.out.println("running = false edirik...");
running = false; // ← Main thread Cache-inə yazdı
// Worker thread GÖRMÜR!
Thread.sleep(2000); // daha 2 saniyə gözlə
System.out.println("Main bitdi!");
// Worker hələ işləyir! ❌
}
}
package az.etibarli;
public class WithVolatile {
// volatile VAR!
private static volatile boolean running = true;
public static void main(String[] args) throws Exception {
Thread worker = new Thread(() -> {
int count = 0;
while (running) { // ← running-i RAM-dan oxuyur!
count++;
}
System.out.println("Worker dayandı! Count: " + count);
});
worker.start();
Thread.sleep(2000); // 2 saniyə gözlə
System.out.println("running = false edirik...");
running = false; // ← BİRBAŞA RAM-a yazdı!
// Worker dərhal GÖRÜR! ✅
Thread.sleep(2000);
System.out.println("Main bitdi!");
}
}
package az.etibarli;
import java.util.Arrays;
import java.util.LinkedList;
import java.util.List;
import java.util.Random;
class Kitchen {
LinkedList<String> meals = new LinkedList<>();
private final int capacity = 8;
public synchronized void addMeal(String chef, String meal) throws Exception {
if (meals.size() == capacity) {
System.out.println("Kitchen is full, " + chef + " is waiting...");
wait();
}
meals.add(meal);
System.out.println(chef + " prepared meal: " + meal);
notify();
}
public synchronized void takeMeal(String waiter) throws Exception {
if (meals.isEmpty()) {
System.out.println("Meal is not ready yet, " + waiter + " is waiting...");
wait();
}
String meal = meals.remove(0);
System.out.println(waiter + " is taking " + meal);
notify();
}
}
class Chef implements Runnable {
private String name;
private Kitchen kitchen;
private List<String> meals = Arrays.asList("Pizza", "Burger", "Pasta", "Sushi", "Salad", "Soup", "Steak", "Kebab");
public Chef(String name, Kitchen kitchen) {
this.name = name;
this.kitchen = kitchen;
}
@Override
public void run() {
Random random = new Random();
try {
while (true) {
String meal = meals.get(random.nextInt(meals.size()));
System.out.println(name + " is preparing " + meal);
Thread.sleep(5000); // ← lock xaricində, Waiter bloklanmır
this.kitchen.addMeal(name, meal);
Thread.sleep(1000);
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
class Waiter implements Runnable {
private String name;
private Kitchen kitchen;
public Waiter(String name, Kitchen kitchen) {
this.name = name;
this.kitchen = kitchen;
}
@Override
public void run() {
try {
while (true) {
this.kitchen.takeMeal(name);
Thread.sleep(2000); // ← lock xaricində
Thread.sleep(1000);
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
public class Task1 {
static void main() {
Kitchen kitchen = new Kitchen();
Chef ali = new Chef("Ali", kitchen);
Waiter nizam = new Waiter("Nizam", kitchen);
Thread t1 = new Thread(ali);
Thread t2 = new Thread(nizam);
t1.start();
t2.start();
}
}
package az.etibarli;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
class Task implements Runnable {
private int id;
public Task(int id) {
this.id = id;
}
@Override
public void run() {
System.out.println("Task with id " + id + " is in work - thread id: " + Thread.currentThread().getName());
long duration = (long) (Math.random() * 5);
try {
TimeUnit.SECONDS.sleep(duration);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
public class SingleThreadExecutor {
static void main() {
ExecutorService executor = Executors.newSingleThreadExecutor();
for (int i = 0; i < 5; i++) {
executor.execute(new Task(i));
}
}
}
Комментарии
Отправить комментарий