forked from PacktPublishing/Java-Coding-Problems
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathAssemblyLine.java
More file actions
150 lines (116 loc) · 4.72 KB
/
AssemblyLine.java
File metadata and controls
150 lines (116 loc) · 4.72 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
package modern.challenge;
import java.util.Queue;
import java.util.Random;
import java.util.concurrent.ConcurrentLinkedQueue;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
import java.util.logging.Logger;
public final class AssemblyLine {
private AssemblyLine() {
throw new AssertionError("There is a single assembly line!");
}
private static final int PRODUCERS = 3;
private static final int CONSUMERS = 2;
private static final int MAX_PROD_TIME_MS = 2 * 1000;
private static final int MAX_CONS_TIME_MS = 2 * 1000;
private static final int TIMEOUT_MS = (MAX_PROD_TIME_MS + MAX_CONS_TIME_MS)
* (PRODUCERS + CONSUMERS);
private static final Logger logger = Logger.getLogger(AssemblyLine.class.getName());
private static final Random rnd = new Random();
private static final Queue<String> queue = new ConcurrentLinkedQueue<>();
private static volatile boolean runningProducer;
private static volatile boolean runningConsumer;
private static final Producer producer = new Producer();
private static final Consumer consumer = new Consumer();
private static ExecutorService producerService;
private static ExecutorService consumerService;
private static class Producer implements Runnable {
@Override
public void run() {
while (runningProducer) {
try {
String bulb = "bulb-" + rnd.nextInt(1000);
Thread.sleep(rnd.nextInt(MAX_PROD_TIME_MS));
queue.offer(bulb);
logger.info(() -> "Checked: " + bulb + " by producer: "
+ Thread.currentThread().getName());
} catch (InterruptedException ex) {
Thread.currentThread().interrupt();
logger.severe(() -> "Exception: " + ex);
break;
}
}
}
}
private static class Consumer implements Runnable {
@Override
public void run() {
while (runningConsumer) {
try {
String bulb = queue.poll();
if (bulb != null) {
Thread.sleep(rnd.nextInt(MAX_CONS_TIME_MS));
logger.info(() -> "Packed: " + bulb + " by consumer: "
+ Thread.currentThread().getName());
}
} catch (InterruptedException ex) {
Thread.currentThread().interrupt();
logger.severe(() -> "Exception: " + ex);
break;
}
}
}
}
public static void startAssemblyLine() {
if (runningProducer || runningConsumer) {
logger.info("Assembly line is already running ...");
return;
}
logger.info("\n\nStarting assembly line ...");
logger.info(() -> "Remaining bulbs from previous run: \n" + queue + "\n\n");
runningProducer = true;
producerService = Executors.newFixedThreadPool(PRODUCERS);
for (int i = 0; i < PRODUCERS; i++) {
producerService.execute(producer);
}
runningConsumer = true;
consumerService = Executors.newFixedThreadPool(CONSUMERS);
for (int i = 0; i < CONSUMERS; i++) {
consumerService.execute(consumer);
}
}
public static void stopAssemblyLine() {
logger.info("Stopping assembly line ...");
boolean isProducerDown = shutdownProducer();
boolean isConsumerDown = shutdownConsumer();
if (!isProducerDown || !isConsumerDown) {
logger.severe("Something abnormal happened during shutting down the assembling line!");
System.exit(0);
}
logger.info("Assembling line was successfully stopped!");
}
private static boolean shutdownProducer() {
runningProducer = false;
return shutdownExecutor(producerService);
}
private static boolean shutdownConsumer() {
runningConsumer = false;
return shutdownExecutor(consumerService);
}
private static boolean shutdownExecutor(ExecutorService executor) {
executor.shutdown();
try {
if (!executor.awaitTermination(TIMEOUT_MS, TimeUnit.MILLISECONDS)) {
executor.shutdownNow();
return executor.awaitTermination(TIMEOUT_MS, TimeUnit.MILLISECONDS);
}
return true;
} catch (InterruptedException ex) {
executor.shutdownNow();
Thread.currentThread().interrupt();
logger.severe(() -> "Exception: " + ex);
}
return false;
}
}