Skip to content

Commit ec811d0

Browse files
Initial Java concurrency demos
0 parents  commit ec811d0

File tree

14 files changed

+424
-0
lines changed

14 files changed

+424
-0
lines changed

.github/workflows/ci.yml

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
name: CI
2+
3+
on:
4+
push:
5+
pull_request:
6+
7+
jobs:
8+
build-and-run:
9+
runs-on: ubuntu-latest
10+
steps:
11+
- name: Checkout
12+
uses: actions/checkout@v4
13+
14+
- name: Set up Java 17
15+
uses: actions/setup-java@v4
16+
with:
17+
distribution: temurin
18+
java-version: '17'
19+
20+
- name: Build demo jar
21+
working-directory: demo
22+
run: |
23+
chmod +x ensure-jdk.sh build.sh run.sh setup.sh
24+
bash -n ensure-jdk.sh build.sh run.sh setup.sh
25+
./build.sh
26+
27+
- name: Run a couple of demos
28+
working-directory: demo
29+
run: |
30+
./run.sh HelloThreads
31+
./run.sh RaceCondition

.gitignore

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
demo/.jdk/
2+
demo/build/
3+
demo/vendor/

README.md

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
# Parallel Computing Course — Java Demos
2+
3+
This repository contains runnable Java examples used in the **Parallel Computing short course** (focus: Java concurrency).
4+
5+
## Quick start
6+
7+
```bash
8+
cd demo
9+
chmod +x setup.sh
10+
./setup.sh
11+
./run.sh HelloThreads
12+
```
13+
14+
## What's inside
15+
16+
- `src/`: Java example sources (default package; easy to run in class)
17+
- `demo/`: one-click scripts to download a local JDK (if needed), compile, package, and run examples
18+
19+
## Requirements
20+
21+
- Linux is the easiest path for the auto-download scripts.
22+
- Any OS works if you have a system JDK 17+ installed.
23+
24+
## Relation to slides
25+
26+
The lecture slides live in a separate repository (PDF + LaTeX). This repo is intended to be **public** so students can browse and run the code.

demo/.gitignore

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
build/
2+
.jdk/
3+
vendor/

demo/README.md

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
# Java demo runner (lecture examples)
2+
3+
This folder compiles the Java examples from `../src/` and packages them into a jar for easy live demos.
4+
5+
## Requirements
6+
7+
- Works best with a system JDK 17+.
8+
- If no JDK is installed, the scripts can auto-download a local JDK (Linux only) into `lectures/demo/.jdk`.
9+
10+
## Build
11+
12+
Easiest (recommended):
13+
14+
```bash
15+
cd lectures/demo
16+
./setup.sh
17+
```
18+
19+
Manual build:
20+
21+
```bash
22+
cd lectures/demo
23+
./build.sh
24+
```
25+
26+
## Run
27+
28+
```bash
29+
cd lectures/demo
30+
./run.sh RaceCondition
31+
./run.sh HelloThreads
32+
./run.sh ProducerConsumerBlockingQueue
33+
./run.sh ExecutorInvokeAll
34+
```
35+
36+
## Offline classroom mode (recommended)
37+
38+
If the classroom network is unreliable, you can pre-download a JDK tarball once and put it into `lectures/demo/vendor/`.
39+
The scripts will prefer the tarball over downloading.
40+
41+
Notes:
42+
- The jar does **not** have a `Main-Class` manifest entry; run by specifying the class name.
43+
- `SynchronizedCounter` is a helper class and does not include `main`.

demo/build.sh

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
#!/usr/bin/env bash
2+
set -euo pipefail
3+
4+
cd "$(dirname "$0")"
5+
6+
# Bootstrap a JDK 17+ if needed (system JDK preferred; otherwise local download).
7+
source ./ensure-jdk.sh
8+
9+
echo "Using: $(javac -version 2>&1)"
10+
11+
rm -rf build
12+
mkdir -p build/classes
13+
14+
# Compile all lecture demo sources (default package).
15+
# --release 17 enforces Java 17 bytecode + API level.
16+
javac --release 17 -encoding UTF-8 -d build/classes ../src/*.java
17+
18+
# Package classes into a runnable classpath jar (no Main-Class needed).
19+
jar --create --file build/demos.jar -C build/classes .
20+
21+
echo
22+
printf "Built %s\n" "$(pwd)/build/demos.jar"
23+
echo "Run an example (class with main):"
24+
echo " ./run.sh HelloThreads"
25+
echo " ./run.sh RaceCondition"
26+
echo " ./run.sh ProducerConsumerBlockingQueue"
27+
echo " ./run.sh ExecutorInvokeAll"

demo/ensure-jdk.sh

Lines changed: 131 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,131 @@
1+
#!/usr/bin/env bash
2+
set -euo pipefail
3+
4+
# Ensures a Java 17+ JDK is available for this demo.
5+
# Strategy:
6+
# 1) Use system JDK if javac exists
7+
# 2) Use local JDK in ./.jdk if present
8+
# 3) Download Temurin JDK 17 into ./.jdk (no sudo required)
9+
# 4) Optionally use a pre-downloaded tarball in ./vendor/
10+
11+
cd "$(dirname "$0")"
12+
13+
need_cmd() {
14+
if ! command -v "$1" >/dev/null 2>&1; then
15+
echo "ERROR: missing required command: $1" >&2
16+
return 1
17+
fi
18+
}
19+
20+
use_local_jdk() {
21+
if [[ -x .jdk/bin/javac ]]; then
22+
export JAVA_HOME="$PWD/.jdk"
23+
export PATH="$JAVA_HOME/bin:$PATH"
24+
return 0
25+
fi
26+
return 1
27+
}
28+
29+
have_system_jdk() {
30+
command -v javac >/dev/null 2>&1 && command -v jar >/dev/null 2>&1
31+
}
32+
33+
adoptium_arch() {
34+
local machine
35+
machine="$(uname -m)"
36+
case "$machine" in
37+
x86_64|amd64) echo "x64" ;;
38+
aarch64|arm64) echo "aarch64" ;;
39+
*)
40+
echo ""
41+
return 1
42+
;;
43+
esac
44+
}
45+
46+
ensure_downloaded_jdk() {
47+
local os arch url tarball extracted top
48+
49+
os="$(uname -s | tr '[:upper:]' '[:lower:]')"
50+
if [[ "$os" != "linux" ]]; then
51+
echo "ERROR: auto-download currently supports Linux only. Please install a JDK 17+ and re-run." >&2
52+
return 1
53+
fi
54+
55+
arch="$(adoptium_arch)" || true
56+
if [[ -z "${arch:-}" ]]; then
57+
echo "ERROR: unsupported CPU architecture: $(uname -m)." >&2
58+
echo "Please install a JDK 17+ manually (or adapt the script)." >&2
59+
return 1
60+
fi
61+
62+
mkdir -p build vendor
63+
64+
# Prefer an instructor-provided offline tarball if present.
65+
# You can drop a file like: vendor/temurin-jdk17.tar.gz
66+
if compgen -G "vendor/*.tar.gz" >/dev/null; then
67+
tarball="$(ls -1 vendor/*.tar.gz | head -n 1)"
68+
echo "Using offline JDK tarball: $tarball"
69+
else
70+
url="https://api.adoptium.net/v3/binary/latest/17/ga/linux/${arch}/jdk/hotspot/normal/eclipse"
71+
tarball="build/temurin-jdk17-linux-${arch}.tar.gz"
72+
73+
if [[ -f "$tarball" ]]; then
74+
echo "Reusing cached download: $tarball"
75+
else
76+
if command -v curl >/dev/null 2>&1; then
77+
echo "Downloading Temurin JDK 17 from Adoptium..."
78+
curl -L --fail --retry 3 --output "$tarball" "$url"
79+
elif command -v wget >/dev/null 2>&1; then
80+
echo "Downloading Temurin JDK 17 from Adoptium..."
81+
wget -O "$tarball" "$url"
82+
else
83+
echo "ERROR: need curl or wget to download a JDK automatically." >&2
84+
echo "Either install a system JDK 17+, or put a JDK tar.gz into lectures/demo/vendor/." >&2
85+
return 1
86+
fi
87+
fi
88+
fi
89+
90+
rm -rf .jdk
91+
92+
# NOTE: This script is sourced by other scripts that run with `set -u`.
93+
# An EXIT trap that references a *local* variable can fail with "unbound variable"
94+
# after the function returns. Use a guarded, global tempdir instead.
95+
_JDK_TMPDIR="$(mktemp -d)"
96+
trap 'if [[ -n "${_JDK_TMPDIR:-}" && -d "${_JDK_TMPDIR:-}" ]]; then rm -rf "$_JDK_TMPDIR"; fi' EXIT
97+
98+
tar -xzf "$tarball" -C "$_JDK_TMPDIR"
99+
top="$(find "$_JDK_TMPDIR" -maxdepth 1 -type d -name 'jdk-*' -o -name 'temurin-*' | head -n 1 || true)"
100+
if [[ -z "${top:-}" ]]; then
101+
# Fallback: use the single directory inside tarball.
102+
top="$(find "$_JDK_TMPDIR" -maxdepth 1 -type d | tail -n +2 | head -n 1 || true)"
103+
fi
104+
105+
if [[ -z "${top:-}" || ! -d "$top" ]]; then
106+
echo "ERROR: could not locate extracted JDK directory." >&2
107+
return 1
108+
fi
109+
110+
mv "$top" .jdk
111+
chmod -R u+rwX .jdk || true
112+
113+
use_local_jdk
114+
}
115+
116+
# 1) system JDK
117+
if have_system_jdk; then
118+
return 0 2>/dev/null || exit 0
119+
fi
120+
121+
# 2) local JDK
122+
if use_local_jdk; then
123+
return 0 2>/dev/null || exit 0
124+
fi
125+
126+
# 3) download into local folder
127+
ensure_downloaded_jdk
128+
129+
# sanity
130+
need_cmd javac
131+
need_cmd jar

demo/run.sh

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
#!/usr/bin/env bash
2+
set -euo pipefail
3+
4+
cd "$(dirname "$0")"
5+
6+
# Ensure a JDK is available; also supports auto-downloaded local JDK.
7+
source ./ensure-jdk.sh
8+
9+
if [[ $# -lt 1 ]]; then
10+
echo "Usage: ./run.sh <MainClass>" >&2
11+
echo
12+
echo "Known runnable classes:" >&2
13+
echo " HelloThreads" >&2
14+
echo " RaceCondition" >&2
15+
echo " ProducerConsumerBlockingQueue" >&2
16+
echo " ExecutorInvokeAll" >&2
17+
exit 2
18+
fi
19+
20+
main_class="$1"
21+
22+
if [[ ! -f build/demos.jar ]]; then
23+
echo "Jar not found; building first..."
24+
./build.sh
25+
fi
26+
27+
java -cp build/demos.jar "$main_class"

demo/setup.sh

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
#!/usr/bin/env bash
2+
set -euo pipefail
3+
4+
cd "$(dirname "$0")"
5+
6+
usage() {
7+
cat <<'EOF'
8+
Usage:
9+
./setup.sh # prepare JDK (if needed) and build demos.jar
10+
./setup.sh --offline # do not download; require system JDK or vendor tarball
11+
./setup.sh --help
12+
13+
What it does:
14+
- Makes demo scripts executable
15+
- Ensures a Java 17+ JDK is available (system JDK or local ./.jdk)
16+
- Builds build/demos.jar from ../code/*.java
17+
18+
Offline mode:
19+
- Put a JDK tar.gz into ./vendor/ (recommended for classroom networks)
20+
- Then run: ./setup.sh --offline
21+
EOF
22+
}
23+
24+
offline=0
25+
case "${1:-}" in
26+
"") ;;
27+
--help|-h) usage; exit 0 ;;
28+
--offline) offline=1 ;;
29+
*)
30+
echo "Unknown option: $1" >&2
31+
usage >&2
32+
exit 2
33+
;;
34+
esac
35+
36+
mkdir -p vendor build
37+
chmod +x ensure-jdk.sh build.sh run.sh || true
38+
39+
if [[ $offline -eq 1 ]]; then
40+
if command -v javac >/dev/null 2>&1 && command -v jar >/dev/null 2>&1; then
41+
: # system JDK ok
42+
elif [[ -x .jdk/bin/javac ]]; then
43+
: # local JDK ok
44+
elif compgen -G "vendor/*.tar.gz" >/dev/null; then
45+
: # vendor tarball ok
46+
else
47+
echo "Offline setup requested, but no JDK found." >&2
48+
echo "Provide one of the following:" >&2
49+
echo " 1) Install a system JDK 17+ (javac/jar)" >&2
50+
echo " 2) Copy a JDK tar.gz into lectures/demo/vendor/" >&2
51+
exit 1
52+
fi
53+
fi
54+
55+
# In offline mode, ensure-jdk.sh will prefer vendor tarball and won't download.
56+
source ./ensure-jdk.sh
57+
58+
./build.sh
59+
60+
echo
61+
echo "Setup complete. Try:"
62+
echo " ./run.sh HelloThreads"
63+
echo " ./run.sh RaceCondition"

src/ExecutorInvokeAll.java

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
import java.util.*;
2+
import java.util.concurrent.*;
3+
4+
public class ExecutorInvokeAll {
5+
public static void main(String[] args) throws Exception {
6+
ExecutorService pool = Executors.newFixedThreadPool(4);
7+
try {
8+
List<Callable<Integer>> tasks = new ArrayList<>();
9+
for (int i = 0; i < 8; i++) { int id = i; tasks.add(() -> id * id); }
10+
for (Future<Integer> f : pool.invokeAll(tasks)) System.out.println(f.get());
11+
} finally { pool.shutdown(); }
12+
}
13+
}

0 commit comments

Comments
 (0)