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
174 lines (130 loc) · 5.15 KB
/
Copy pathAssemblyLine.java
File metadata and controls
174 lines (130 loc) · 5.15 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
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
package modern.challenge;
import java.util.Random;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
import java.util.logging.Logger;
public final class AssemblyLine {
private AssemblyLine() {
throw new AssertionError("There is a single assembly line!");
}
private static final int MAX_PROD_TIME_MS = 5 * 1000;
private static final int MAX_CONS_TIME_MS = 3 * 1000;
private static final int TIMEOUT_MS = MAX_PROD_TIME_MS + MAX_CONS_TIME_MS + 1000;
private static final Logger logger = Logger.getLogger(AssemblyLine.class.getName());
private static final Random rnd = new Random();
private static volatile boolean runningProducer;
private static volatile boolean runningConsumer;
private static ExecutorService producerService;
private static ExecutorService consumerService;
private static class Producer implements Callable {
private final String bulb;
private Producer(String bulb) {
this.bulb = bulb;
}
@Override
public String call() throws DefectBulbException, InterruptedException {
if (runningProducer) {
Thread.sleep(rnd.nextInt(MAX_PROD_TIME_MS));
if (rnd.nextInt(100) < 5) {
throw new DefectBulbException("Defect: " + bulb);
} else {
logger.info(() -> "Checked: " + bulb);
}
return bulb;
}
return "";
}
}
private static class Consumer implements Runnable {
private final String bulb;
private Consumer(String bulb) {
this.bulb = bulb;
}
@Override
public void run() {
if (runningConsumer) {
try {
Thread.sleep(rnd.nextInt(MAX_CONS_TIME_MS));
logger.info(() -> "Packed: " + bulb);
} catch (InterruptedException ex) {
Thread.currentThread().interrupt();
logger.severe(() -> "Exception: " + ex);
}
}
}
}
public static void startAssemblyLine() {
if (runningProducer || runningConsumer) {
logger.info("Assembly line is already running ...");
return;
}
logger.info("\n\nStarting assembly line ...");
runningProducer = true;
consumerService = Executors.newSingleThreadExecutor();
runningConsumer = true;
producerService = Executors.newSingleThreadExecutor();
new Thread(() -> {
automaticSystem();
}).start();
}
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!");
}
@SuppressWarnings("unchecked")
private static void automaticSystem() {
while (runningProducer && runningConsumer) {
String bulb = "bulb-" + rnd.nextInt(1000);
Producer producer = new Producer(bulb);
Future<String> bulbFuture = producerService.submit(producer);
try {
String checkedBulb = bulbFuture.get(MAX_PROD_TIME_MS + 1000, TimeUnit.MILLISECONDS);
Consumer consumer = new Consumer(checkedBulb);
if (runningConsumer) {
consumerService.execute(consumer);
}
} catch (ExecutionException ex) {
logger.severe(() -> "Exception: " + ex.getCause());
} catch (InterruptedException ex) {
Thread.currentThread().interrupt();
logger.severe(() -> "Exception: " + ex);
} catch (TimeoutException ex) {
logger.severe("The producer doesn't respect the checking time!");
}
}
}
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;
}
}