Skip to content

Commit 9bf47c5

Browse files
committed
Add Multithreading (part I) and Network Programming (part II) code snippets
1 parent 21b51c0 commit 9bf47c5

12 files changed

Lines changed: 404 additions & 0 deletions

10-network/snippets/README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
# Многонишково програмиране (част II) и Мрежово програмиране (част I) / Code snippets
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
void main() throws IOException {
2+
3+
InetAddress address = InetAddress.getByName("www.google.com");
4+
IO.println(address.getHostAddress()); // 172.217.17.132
5+
6+
address = InetAddress.getByName("62.44.101.151");
7+
IO.println(address.getHostName()); // learn.fmi.uni-sofia.bg
8+
9+
IO.println(address.isReachable(5_000)); // true
10+
11+
InetAddress localhost = InetAddress.getLocalHost();
12+
IO.println(localhost.getHostAddress()); // IP associated with your hostname,
13+
// typically LAN IP (192.168.x.x)
14+
15+
// Think of:
16+
// - LAN IP = your apartment number
17+
// - Public IP = the street address for the whole building
18+
// - 127.0.0.1 = your own room inside your apartment (only you can reach it)
19+
20+
}
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
void main() throws Exception {
2+
InetAddress lanIp = getLanIp();
3+
IO.println(lanIp);
4+
}
5+
6+
public static InetAddress getLanIp() throws SocketException {
7+
Enumeration<NetworkInterface> nics = NetworkInterface.getNetworkInterfaces();
8+
9+
while (nics.hasMoreElements()) {
10+
NetworkInterface nic = nics.nextElement();
11+
12+
// Skip loopback, down, or virtual interfaces
13+
if (!nic.isUp() || nic.isLoopback() || nic.isVirtual()) {
14+
continue;
15+
}
16+
17+
Enumeration<InetAddress> addrs = nic.getInetAddresses();
18+
while (addrs.hasMoreElements()) {
19+
InetAddress addr = addrs.nextElement();
20+
21+
// We want only IPv4 addresses and exclude loopback
22+
if (addr instanceof Inet4Address && !addr.isLoopbackAddress()) {
23+
return addr;
24+
}
25+
}
26+
}
27+
return null; // or throw exception if required
28+
}
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
void main() throws Exception {
2+
3+
Enumeration<NetworkInterface> interfaces = NetworkInterface.getNetworkInterfaces();
4+
5+
while (interfaces.hasMoreElements()) {
6+
NetworkInterface nic = interfaces.nextElement();
7+
8+
IO.println("----------------------------------------------------");
9+
IO.println("Name : " + nic.getName());
10+
IO.println("Up : " + nic.isUp());
11+
IO.println("Loopback : " + nic.isLoopback());
12+
IO.println("Virtual : " + nic.isVirtual());
13+
IO.println("PointToPoint : " + nic.isPointToPoint());
14+
IO.println("MTU : " + nic.getMTU());
15+
16+
byte[] mac = nic.getHardwareAddress();
17+
IO.print("MAC Address : ");
18+
if (mac != null) {
19+
for (int i = 0; i < mac.length; i++) {
20+
System.out.printf("%02X%s", mac[i], (i < mac.length - 1) ? "-" : "");
21+
}
22+
IO.println();
23+
} else {
24+
IO.println("N/A");
25+
}
26+
27+
// List all IPv4/IPv6 addresses
28+
IO.println("IP Addresses :");
29+
Enumeration<InetAddress> addrs = nic.getInetAddresses();
30+
while (addrs.hasMoreElements()) {
31+
InetAddress addr = addrs.nextElement();
32+
IO.println(" - " + addr.getHostAddress());
33+
}
34+
IO.println();
35+
}
36+
37+
}
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
/*
2+
* Structured Concurrency Example in Java 25
3+
*
4+
* This example demonstrates Java's StructuredTaskScope, a preview feature in Java 25.
5+
* Structured concurrency allows you to fork multiple tasks within a scope, wait for all
6+
* of them to complete, and handle exceptions in a structured way.
7+
*
8+
* Key points:
9+
* 1. Tasks are forked concurrently using scope.fork().
10+
* 2. scope.join() waits for all tasks to finish and throws FailedException if any task fails.
11+
* 3. Results are retrieved using subtask.get() after join().
12+
* 4. Any running tasks are automatically cancelled if one fails.
13+
*
14+
* This makes concurrent code easier to read, safer, and less error-prone than manual thread management.
15+
*/
16+
17+
void main() {
18+
// Open a structured task scope
19+
try (var scope = StructuredTaskScope.<String>open()) {
20+
21+
// Fork tasks concurrently
22+
var task1 = scope.fork(() -> work("Task 1", 1000));
23+
var task2 = scope.fork(() -> work("Task 2 (fails)", 500));
24+
var task3 = scope.fork(() -> work("Task 3", 800));
25+
26+
// Wait for all tasks to complete; throws FailedException if any task failed
27+
scope.join();
28+
29+
// Retrieve results using get() after join() succeeds
30+
IO.println(task1.get());
31+
IO.println(task2.get());
32+
IO.println(task3.get());
33+
34+
} catch (StructuredTaskScope.FailedException e) {
35+
IO.println("One or more tasks failed: " + e.getCause());
36+
} catch (InterruptedException e) {
37+
IO.println("Interrupted while waiting for tasks.");
38+
}
39+
}
40+
41+
private static String work(String name, int delayMillis) throws Exception {
42+
Thread.sleep(delayMillis);
43+
if (name.contains("fails")) {
44+
throw new RuntimeException(name + " encountered an error!");
45+
}
46+
return name + " completed successfully";
47+
}
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
package threadpools;
2+
3+
import java.util.concurrent.ExecutorService;
4+
import java.util.concurrent.Executors;
5+
6+
public class CachedThreadPoolExample {
7+
8+
// A cached thread pool will reuse available threads, but if all threads are busy
9+
// and more tasks are submitted, it will create new threads.
10+
// If a thread is idle for 60s, it will be decommissioned.
11+
12+
private static final int MAX_TASKS = 15;
13+
14+
static void main() {
15+
16+
// Creates a thread pool with a fixed number of threads
17+
ExecutorService executor = Executors.newCachedThreadPool();
18+
19+
// Submit tasks to the executor.
20+
for (int i = 0; i < MAX_TASKS; i++) {
21+
Runnable task = new Task("" + i);
22+
executor.execute(task); // Execute the task using the thread pool.
23+
}
24+
25+
// Shutdown the executor service. It will not accept new tasks but complete existing ones.
26+
executor.shutdown();
27+
}
28+
}
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
package threadpools;
2+
3+
import java.util.concurrent.ExecutorService;
4+
import java.util.concurrent.Executors;
5+
6+
public class FixedThreadPoolExample {
7+
8+
// A fixed thread pool contains a specified number of threads. If all threads are busy
9+
// and additional tasks are submitted, they will wait in the queue until a thread is available.
10+
11+
private static final int MAX_THREADS = 3;
12+
private static final int MAX_TASKS = 15;
13+
14+
static void main() {
15+
16+
// Creates a thread pool with a fixed number of threads
17+
ExecutorService executor = Executors.newFixedThreadPool(MAX_THREADS);
18+
19+
// Submit tasks to the executor.
20+
for (int i = 0; i < MAX_TASKS; i++) {
21+
Runnable task = new Task("" + i);
22+
executor.execute(task); // Execute the task using the thread pool.
23+
}
24+
25+
// Shutdown the executor service. It will not accept new tasks but complete existing ones.
26+
executor.shutdown();
27+
}
28+
}
Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
package threadpools;
2+
3+
import java.util.concurrent.Executors;
4+
import java.util.concurrent.ScheduledExecutorService;
5+
import java.util.concurrent.TimeUnit;
6+
7+
public class ScheduledThreadPoolExample {
8+
9+
// A scheduled thread pool is used for scheduling tasks
10+
// to execute after a delay or to execute periodically.
11+
12+
static void main() throws InterruptedException {
13+
14+
// Creates a scheduled thread pool with 2 threads.
15+
ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(10);
16+
17+
// Schedule tasks
18+
scheduler.schedule(() -> System.out.println("Delayed task executed after 5 seconds"), 5, TimeUnit.SECONDS);
19+
20+
// Schedule a task to repeat at a fixed rate.
21+
// The interval is based on the scheduled start time of each execution, maintaining a strict execution schedule
22+
// which may lead to task overlap if execution time exceeds the scheduled rate.
23+
scheduler.scheduleAtFixedRate(() -> {
24+
doSomeWork(2_000);
25+
System.out.println("Some regular task executed at fixed rate by " + Thread.currentThread().getName());
26+
}, 0, 1, TimeUnit.SECONDS);
27+
28+
// Schedule a task to repeat with a fixed delay based on the actual completion time of the previous execution,
29+
// providing buffer time if the task takes longer, preventing task overlap.
30+
scheduler.scheduleWithFixedDelay(() -> {
31+
doSomeWork(2_000);
32+
System.out.println("Some regular task executed with fixed delay by " + Thread.currentThread().getName());
33+
}, 0, 1, TimeUnit.SECONDS);
34+
35+
// Shut down the scheduler after some delay to allow time for tasks to execute.
36+
scheduler.schedule(() -> scheduler.shutdown(), 20, TimeUnit.SECONDS);
37+
38+
}
39+
40+
private static void doSomeWork(long millis) {
41+
try {
42+
Thread.sleep(millis);
43+
} catch (InterruptedException e) {
44+
throw new RuntimeException(e);
45+
}
46+
}
47+
48+
}
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
package threadpools;
2+
3+
public class Task implements Runnable {
4+
private final String taskId;
5+
6+
public Task(String id) {
7+
this.taskId = id;
8+
}
9+
10+
@Override
11+
public void run() {
12+
System.out.println("Executing Task Id: " + taskId + ", by " + Thread.currentThread().getName());
13+
try {
14+
Thread.sleep(1_000); // Simulate some work with a sleep.
15+
} catch (InterruptedException e) {
16+
e.printStackTrace();
17+
}
18+
}
19+
20+
}
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
package threadpools;
2+
3+
import java.util.concurrent.ExecutorService;
4+
import java.util.concurrent.Executors;
5+
6+
public class VirtualThreadPoolExample {
7+
8+
static void main() {
9+
10+
// Create an executor service using a new virtual threads for every new task
11+
ExecutorService executorService = Executors.newVirtualThreadPerTaskExecutor();
12+
13+
try (executorService) {
14+
15+
// Submit several tasks to the executor
16+
for (int i = 0; i < 10; i++) {
17+
18+
final int taskId = i;
19+
20+
executorService.submit(() -> {
21+
// Note that virtual threads are created without a name by default to minimize overhead
22+
// and because the high number of threads typically makes naming them impractical.
23+
System.out.println("Running task " + taskId + " in " + Thread.currentThread());
24+
25+
// Simulate some work with sleep
26+
try {
27+
Thread.sleep(1_000);
28+
} catch (InterruptedException e) {
29+
e.printStackTrace();
30+
}
31+
});
32+
}
33+
34+
} // executorService will be autoclosed --> auto shut down
35+
36+
}
37+
}

0 commit comments

Comments
 (0)