Commit 92bb24e3 authored by Andy Wilkinson's avatar Andy Wilkinson

Avoid synchronizing on this and use an internal monitor instead

Where possible, code that previously synchronized on this (or on the
class in the case of static methods) has been updated to use an
internal monitor object instead. This allows the locking model that's
employed to be an implementation detail rather than part of the
class's API.

Classes that override a synchronized method continue to declare
the overriding method as synchronized. This ensures that locking
is consistent across the superclass and its subclass.

Closes gh-6262
parent f9c7db11
......@@ -33,6 +33,8 @@ public class InMemoryAuditEventRepository implements AuditEventRepository {
private static final int DEFAULT_CAPACITY = 4000;
private final Object monitor = new Object();
/**
* Circular buffer of the event with tail pointing to the last element.
*/
......@@ -52,36 +54,42 @@ public class InMemoryAuditEventRepository implements AuditEventRepository {
* Set the capacity of this event repository.
* @param capacity the capacity
*/
public synchronized void setCapacity(int capacity) {
public void setCapacity(int capacity) {
synchronized (this.monitor) {
this.events = new AuditEvent[capacity];
}
}
@Override
public synchronized void add(AuditEvent event) {
public void add(AuditEvent event) {
Assert.notNull(event, "AuditEvent must not be null");
synchronized (this.monitor) {
this.tail = (this.tail + 1) % this.events.length;
this.events[this.tail] = event;
}
}
@Override
public synchronized List<AuditEvent> find(Date after) {
public List<AuditEvent> find(Date after) {
return find(null, after, null);
}
@Override
public synchronized List<AuditEvent> find(String principal, Date after) {
public List<AuditEvent> find(String principal, Date after) {
return find(principal, after, null);
}
@Override
public synchronized List<AuditEvent> find(String principal, Date after, String type) {
public List<AuditEvent> find(String principal, Date after, String type) {
LinkedList<AuditEvent> events = new LinkedList<AuditEvent>();
synchronized (this.events) {
for (int i = 0; i < this.events.length; i++) {
AuditEvent event = resolveTailEvent(i);
if (event != null && isMatch(principal, after, type, event)) {
events.addFirst(event);
}
}
}
return events;
}
......
......@@ -88,8 +88,8 @@ public class MailHealthIndicatorTests {
}
@Override
public synchronized void connect(String host, int port, String user,
String password) throws MessagingException {
public void connect(String host, int port, String user, String password)
throws MessagingException {
}
@Override
......
......@@ -61,6 +61,8 @@ public class RunCommand extends OptionParsingCommand {
private static class RunOptionHandler extends CompilerOptionHandler {
private final Object monitor = new Object();
private OptionSpec<Void> watchOption;
private OptionSpec<Void> verboseOption;
......@@ -77,16 +79,18 @@ public class RunCommand extends OptionParsingCommand {
this.quietOption = option(Arrays.asList("quiet", "q"), "Quiet logging");
}
public synchronized void stop() {
public void stop() {
synchronized (this.monitor) {
if (this.runner != null) {
this.runner.stop();
}
this.runner = null;
}
}
@Override
protected synchronized ExitStatus run(OptionSet options) throws Exception {
synchronized (this.monitor) {
if (this.runner != null) {
throw new RuntimeException(
"Already running. Please stop the current application before running another (use the 'stop' command).");
......@@ -108,6 +112,7 @@ public class RunCommand extends OptionParsingCommand {
return ExitStatus.OK;
}
}
/**
* Simple adapter class to present the {@link OptionSet} as a
......
/*
* Copyright 2012-2014 the original author or authors.
* Copyright 2012-2016 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
......@@ -45,6 +45,8 @@ public class SpringApplicationRunner {
private static int runnerCounter = 0;
private final Object monitor = new Object();
private final SpringApplicationRunnerConfiguration configuration;
private final String[] sources;
......@@ -84,11 +86,12 @@ public class SpringApplicationRunner {
}
/**
* Compile and run the application. This method is synchronized as it can be called by
* file monitoring threads.
* Compile and run the application.
*
* @throws Exception on error
*/
public synchronized void compileAndRun() throws Exception {
public void compileAndRun() throws Exception {
synchronized (this.monitor) {
try {
stop();
Object[] compiledSources = compile();
......@@ -107,13 +110,16 @@ public class SpringApplicationRunner {
}
}
}
}
public void stop() {
synchronized (this.monitor) {
if (this.runThread != null) {
this.runThread.shutdown();
this.runThread = null;
}
}
}
private Object[] compile() throws IOException {
Object[] compiledSources = this.compiler.compile(this.sources);
......@@ -136,6 +142,8 @@ public class SpringApplicationRunner {
*/
private class RunThread extends Thread {
private final Object monitor = new Object();
private final Object[] compiledSources;
private Object applicationContext;
......@@ -155,6 +163,7 @@ public class SpringApplicationRunner {
@Override
public void run() {
synchronized (this.monitor) {
try {
this.applicationContext = new SpringApplicationLauncher(
getContextClassLoader()).launch(this.compiledSources,
......@@ -164,14 +173,17 @@ public class SpringApplicationRunner {
ex.printStackTrace();
}
}
}
/**
* Shutdown the thread, closing any previously opened application context.
*/
public synchronized void shutdown() {
public void shutdown() {
synchronized (this.monitor) {
if (this.applicationContext != null) {
try {
Method method = this.applicationContext.getClass().getMethod("close");
Method method = this.applicationContext.getClass()
.getMethod("close");
method.invoke(this.applicationContext);
}
catch (NoSuchMethodException ex) {
......@@ -186,6 +198,7 @@ public class SpringApplicationRunner {
}
}
}
}
/**
* Thread to watch for file changes and trigger recompile/reload.
......
/*
* Copyright 2012-2015 the original author or authors.
* Copyright 2012-2016 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
......@@ -139,7 +139,7 @@ class Connection {
}
}
private synchronized void writeWebSocketFrame(Frame frame) throws IOException {
private void writeWebSocketFrame(Frame frame) throws IOException {
frame.write(this.outputStream);
}
......
......@@ -53,6 +53,13 @@ public class LiveReloadServer {
private static final int READ_TIMEOUT = (int) TimeUnit.SECONDS.toMillis(4);
private final ExecutorService executor = Executors
.newCachedThreadPool(new WorkerThreadFactory());
private final List<Connection> connections = new ArrayList<Connection>();
private final Object monitor = new Object();
private final int port;
private final ThreadFactory threadFactory;
......@@ -61,11 +68,6 @@ public class LiveReloadServer {
private Thread listenThread;
private ExecutorService executor = Executors
.newCachedThreadPool(new WorkerThreadFactory());
private List<Connection> connections = new ArrayList<Connection>();
/**
* Create a new {@link LiveReloadServer} listening on the default port.
*/
......@@ -112,7 +114,8 @@ public class LiveReloadServer {
* Start the livereload server and accept incoming connections.
* @throws IOException in case of I/O errors
*/
public synchronized void start() throws IOException {
public void start() throws IOException {
synchronized (this.monitor) {
Assert.state(!isStarted(), "Server already started");
logger.debug("Starting live reload server on port " + this.port);
this.serverSocket = new ServerSocket(this.port);
......@@ -128,14 +131,17 @@ public class LiveReloadServer {
this.listenThread.setName("Live Reload Server");
this.listenThread.start();
}
}
/**
* Return if the server has been started.
* @return {@code true} if the server is running
*/
public synchronized boolean isStarted() {
public boolean isStarted() {
synchronized (this.monitor) {
return this.listenThread != null;
}
}
/**
* Return the port that the server is listening on.
......@@ -168,7 +174,8 @@ public class LiveReloadServer {
* Gracefully stop the livereload server.
* @throws IOException in case of I/O errors
*/
public synchronized void stop() throws IOException {
public void stop() throws IOException {
synchronized (this.monitor) {
if (this.listenThread != null) {
closeAllConnections();
try {
......@@ -189,9 +196,10 @@ public class LiveReloadServer {
this.serverSocket = null;
}
}
}
private void closeAllConnections() throws IOException {
synchronized (this.connections) {
synchronized (this.monitor) {
for (Connection connection : this.connections) {
connection.close();
}
......@@ -202,7 +210,7 @@ public class LiveReloadServer {
* Trigger livereload of all connected clients.
*/
public void triggerReload() {
synchronized (this.connections) {
synchronized (this.monitor) {
for (Connection connection : this.connections) {
try {
connection.triggerReload();
......@@ -215,13 +223,13 @@ public class LiveReloadServer {
}
private void addConnection(Connection connection) {
synchronized (this.connections) {
synchronized (this.monitor) {
this.connections.add(connection);
}
}
private void removeConnection(Connection connection) {
synchronized (this.connections) {
synchronized (this.monitor) {
this.connections.remove(connection);
}
}
......
......@@ -80,10 +80,24 @@ import org.springframework.util.ReflectionUtils;
*/
public class Restarter {
private static final Object INSTANCE_MONITOR = new Object();
private static final String[] NO_ARGS = {};
private static Restarter instance;
private final Set<URL> urls = new LinkedHashSet<URL>();
private final ClassLoaderFiles classLoaderFiles = new ClassLoaderFiles();
private final Map<String, Object> attributes = new HashMap<String, Object>();
private final BlockingDeque<LeakSafeThread> leakSafeThreads = new LinkedBlockingDeque<LeakSafeThread>();
private final Lock stopLock = new ReentrantLock();
private final Object monitor = new Object();
private Log logger = new DeferredLog();
private final boolean forceReferenceCleanup;
......@@ -100,18 +114,8 @@ public class Restarter {
private final UncaughtExceptionHandler exceptionHandler;
private final Set<URL> urls = new LinkedHashSet<URL>();
private final ClassLoaderFiles classLoaderFiles = new ClassLoaderFiles();
private final Map<String, Object> attributes = new HashMap<String, Object>();
private final BlockingDeque<LeakSafeThread> leakSafeThreads = new LinkedBlockingDeque<LeakSafeThread>();
private boolean finished = false;
private final Lock stopLock = new ReentrantLock();
private volatile ConfigurableApplicationContext rootContext;
/**
......@@ -394,16 +398,21 @@ public class Restarter {
* Called to finish {@link Restarter} initialization when application logging is
* available.
*/
synchronized void finish() {
void finish() {
synchronized (this.monitor) {
if (!isFinished()) {
this.logger = DeferredLog.replay(this.logger, LogFactory.getLog(getClass()));
this.logger = DeferredLog.replay(this.logger,
LogFactory.getLog(getClass()));
this.finished = true;
}
}
}
synchronized boolean isFinished() {
boolean isFinished() {
synchronized (this.monitor) {
return this.finished;
}
}
void prepare(ConfigurableApplicationContext applicationContext) {
if (applicationContext != null && applicationContext.getParent() != null) {
......@@ -514,7 +523,7 @@ public class Restarter {
public static void initialize(String[] args, boolean forceReferenceCleanup,
RestartInitializer initializer, boolean restartOnInitialize) {
Restarter localInstance = null;
synchronized (Restarter.class) {
synchronized (INSTANCE_MONITOR) {
if (instance == null) {
localInstance = new Restarter(Thread.currentThread(), args,
forceReferenceCleanup, initializer);
......@@ -531,26 +540,32 @@ public class Restarter {
* {@link #initialize(String[]) initialization}.
* @return the restarter
*/
public synchronized static Restarter getInstance() {
public static Restarter getInstance() {
synchronized (INSTANCE_MONITOR) {
Assert.state(instance != null, "Restarter has not been initialized");
return instance;
}
}
/**
* Set the restarter instance (useful for testing).
* @param instance the instance to set
*/
final static void setInstance(Restarter instance) {
synchronized (INSTANCE_MONITOR) {
Restarter.instance = instance;
}
}
/**
* Clear the instance. Primarily provided for tests and not usually used in
* application code.
*/
public static void clearInstance() {
synchronized (INSTANCE_MONITOR) {
instance = null;
}
}
/**
* Thread that is created early so not to retain the {@link RestartClassLoader}.
......
......@@ -150,7 +150,7 @@ public class HttpTunnelConnection implements TunnelConnection {
return size;
}
private synchronized void openNewConnection(final HttpTunnelPayload payload) {
private void openNewConnection(final HttpTunnelPayload payload) {
HttpTunnelConnection.this.executor.execute(new Runnable() {
@Override
......
......@@ -46,12 +46,14 @@ public class TunnelClient implements SmartInitializingSingleton {
private static final Log logger = LogFactory.getLog(TunnelClient.class);
private final TunnelClientListeners listeners = new TunnelClientListeners();
private final Object monitor = new Object();
private final int listenPort;
private final TunnelConnection tunnelConnection;
private TunnelClientListeners listeners = new TunnelClientListeners();
private ServerThread serverThread;
public TunnelClient(int listenPort, TunnelConnection tunnelConnection) {
......@@ -63,6 +65,7 @@ public class TunnelClient implements SmartInitializingSingleton {
@Override
public void afterSingletonsInstantiated() {
synchronized (this.monitor) {
if (this.serverThread == null) {
try {
start();
......@@ -72,25 +75,30 @@ public class TunnelClient implements SmartInitializingSingleton {
}
}
}
}
/**
* Start the client and accept incoming connections on the port.
* @throws IOException in case of I/O errors
*/
public synchronized void start() throws IOException {
public void start() throws IOException {
synchronized (this.monitor) {
Assert.state(this.serverThread == null, "Server already started");
ServerSocketChannel serverSocketChannel = ServerSocketChannel.open();
serverSocketChannel.socket().bind(new InetSocketAddress(this.listenPort));
logger.trace("Listening for TCP traffic to tunnel on port " + this.listenPort);
logger.trace(
"Listening for TCP traffic to tunnel on port " + this.listenPort);
this.serverThread = new ServerThread(serverSocketChannel);
this.serverThread.start();
}
}
/**
* Stop the client, disconnecting any servers.
* @throws IOException in case of I/O errors
*/
public synchronized void stop() throws IOException {
public void stop() throws IOException {
synchronized (this.monitor) {
if (this.serverThread != null) {
logger.trace("Closing tunnel client on port " + this.listenPort);
this.serverThread.close();
......@@ -103,10 +111,13 @@ public class TunnelClient implements SmartInitializingSingleton {
this.serverThread = null;
}
}
}
protected final ServerThread getServerThread() {
synchronized (this.monitor) {
return this.serverThread;
}
}
public void addListener(TunnelClientListener listener) {
this.listeners.addListener(listener);
......
/*
* Copyright 2012-2015 the original author or authors.
* Copyright 2012-2016 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
......@@ -17,8 +17,8 @@
package org.springframework.boot.devtools.tunnel.client;
import java.nio.channels.SocketChannel;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.CopyOnWriteArrayList;
import org.springframework.util.Assert;
......@@ -29,7 +29,7 @@ import org.springframework.util.Assert;
*/
class TunnelClientListeners {
private final List<TunnelClientListener> listeners = new ArrayList<TunnelClientListener>();
private final List<TunnelClientListener> listeners = new CopyOnWriteArrayList<TunnelClientListener>();
public void addListener(TunnelClientListener listener) {
Assert.notNull(listener, "Listener must not be null");
......
......@@ -34,12 +34,14 @@ public class HttpTunnelPayloadForwarder {
private static final int MAXIMUM_QUEUE_SIZE = 100;
private final Map<Long, HttpTunnelPayload> queue = new HashMap<Long, HttpTunnelPayload>();
private final Object monitor = new Object();
private final WritableByteChannel targetChannel;
private long lastRequestSeq = 0;
private final Map<Long, HttpTunnelPayload> queue = new HashMap<Long, HttpTunnelPayload>();
/**
* Create a new {@link HttpTunnelPayloadForwarder} instance.
* @param targetChannel the target channel
......@@ -49,7 +51,8 @@ public class HttpTunnelPayloadForwarder {
this.targetChannel = targetChannel;
}
public synchronized void forward(HttpTunnelPayload payload) throws IOException {
public void forward(HttpTunnelPayload payload) throws IOException {
synchronized (this.monitor) {
long seq = payload.getSequence();
if (this.lastRequestSeq != seq - 1) {
Assert.state(this.queue.size() < MAXIMUM_QUEUE_SIZE,
......@@ -65,5 +68,6 @@ public class HttpTunnelPayloadForwarder {
forward(queuedItem);
}
}
}
}
......@@ -28,14 +28,21 @@ public class Snake {
private static final int DEFAULT_LENGTH = 5;
private final Deque<Location> tail = new ArrayDeque<Location>();
private final Object monitor = new Object();
private final int id;
private final WebSocketSession session;
private final String hexColor;
private Direction direction;
private int length = DEFAULT_LENGTH;
private Location head;
private final Deque<Location> tail = new ArrayDeque<Location>();
private final String hexColor;
public Snake(int id, WebSocketSession session) {
this.id = id;
......@@ -51,21 +58,26 @@ public class Snake {
this.length = DEFAULT_LENGTH;
}
private synchronized void kill() throws Exception {
private void kill() throws Exception {
synchronized (this.monitor) {
resetState();
sendMessage("{'type': 'dead'}");
}
}
private synchronized void reward() throws Exception {
private void reward() throws Exception {
synchronized (this.monitor) {
this.length++;
sendMessage("{'type': 'kill'}");
}
}
protected void sendMessage(String msg) throws Exception {
this.session.sendMessage(new TextMessage(msg));
}
public synchronized void update(Collection<Snake> snakes) throws Exception {
public void update(Collection<Snake> snakes) throws Exception {
synchronized (this.monitor) {
Location nextLocation = this.head.getAdjacentLocation(this.direction);
if (nextLocation.x >= SnakeUtils.PLAYFIELD_WIDTH) {
nextLocation.x = 0;
......@@ -89,6 +101,7 @@ public class Snake {
handleCollisions(snakes);
}
}
private void handleCollisions(Collection<Snake> snakes) throws Exception {
for (Snake snake : snakes) {
......@@ -104,19 +117,26 @@ public class Snake {
}
}
public synchronized Location getHead() {
public Location getHead() {
synchronized (this.monitor) {
return this.head;
}
}
public synchronized Collection<Location> getTail() {
public Collection<Location> getTail() {
synchronized (this.monitor) {
return this.tail;
}
}
public synchronized void setDirection(Direction direction) {
public void setDirection(Direction direction) {
synchronized (this.monitor) {
this.direction = direction;
}
}
public synchronized String getLocationsJson() {
public String getLocationsJson() {
synchronized (this.monitor) {
StringBuilder sb = new StringBuilder();
sb.append(String.format("{x: %d, y: %d}", Integer.valueOf(this.head.x),
Integer.valueOf(this.head.y)));
......@@ -128,6 +148,7 @@ public class Snake {
return String.format("{'id':%d,'body':[%s]}", Integer.valueOf(this.id),
sb.toString());
}
}
public int getId() {
return this.id;
......
......@@ -33,31 +33,37 @@ import org.slf4j.LoggerFactory;
*/
public class SnakeTimer {
private static final Logger log = LoggerFactory.getLogger(SnakeTimer.class);
private static final long TICK_DELAY = 100;
private static Timer gameTimer = null;
private static final Object MONITOR = new Object();
private static final long TICK_DELAY = 100;
private static final Logger log = LoggerFactory.getLogger(SnakeTimer.class);
private static final ConcurrentHashMap<Integer, Snake> snakes = new ConcurrentHashMap<Integer, Snake>();
public static synchronized void addSnake(Snake snake) {
private static Timer gameTimer = null;
public static void addSnake(Snake snake) {
synchronized (MONITOR) {
if (snakes.isEmpty()) {
startTimer();
}
snakes.put(Integer.valueOf(snake.getId()), snake);
}
}
public static Collection<Snake> getSnakes() {
return Collections.unmodifiableCollection(snakes.values());
}
public static synchronized void removeSnake(Snake snake) {
public static void removeSnake(Snake snake) {
synchronized (MONITOR) {
snakes.remove(Integer.valueOf(snake.getId()));
if (snakes.isEmpty()) {
stopTimer();
}
}
}
public static void tick() throws Exception {
StringBuilder sb = new StringBuilder();
......
......@@ -28,14 +28,21 @@ public class Snake {
private static final int DEFAULT_LENGTH = 5;
private final Deque<Location> tail = new ArrayDeque<Location>();
private final Object monitor = new Object();
private final int id;
private final WebSocketSession session;
private final String hexColor;
private Direction direction;
private int length = DEFAULT_LENGTH;
private Location head;
private final Deque<Location> tail = new ArrayDeque<Location>();
private final String hexColor;
public Snake(int id, WebSocketSession session) {
this.id = id;
......@@ -51,21 +58,26 @@ public class Snake {
this.length = DEFAULT_LENGTH;
}
private synchronized void kill() throws Exception {
private void kill() throws Exception {
synchronized (this.monitor) {
resetState();
sendMessage("{'type': 'dead'}");
}
}
private synchronized void reward() throws Exception {
private void reward() throws Exception {
synchronized (this.monitor) {
this.length++;
sendMessage("{'type': 'kill'}");
}
}
protected void sendMessage(String msg) throws Exception {
this.session.sendMessage(new TextMessage(msg));
}
public synchronized void update(Collection<Snake> snakes) throws Exception {
public void update(Collection<Snake> snakes) throws Exception {
synchronized (this.monitor) {
Location nextLocation = this.head.getAdjacentLocation(this.direction);
if (nextLocation.x >= SnakeUtils.PLAYFIELD_WIDTH) {
nextLocation.x = 0;
......@@ -89,6 +101,7 @@ public class Snake {
handleCollisions(snakes);
}
}
private void handleCollisions(Collection<Snake> snakes) throws Exception {
for (Snake snake : snakes) {
......@@ -104,19 +117,26 @@ public class Snake {
}
}
public synchronized Location getHead() {
public Location getHead() {
synchronized (this.monitor) {
return this.head;
}
}
public synchronized Collection<Location> getTail() {
public Collection<Location> getTail() {
synchronized (this.monitor) {
return this.tail;
}
}
public synchronized void setDirection(Direction direction) {
public void setDirection(Direction direction) {
synchronized (this.monitor) {
this.direction = direction;
}
}
public synchronized String getLocationsJson() {
public String getLocationsJson() {
synchronized (this.monitor) {
StringBuilder sb = new StringBuilder();
sb.append(String.format("{x: %d, y: %d}", Integer.valueOf(this.head.x),
Integer.valueOf(this.head.y)));
......@@ -128,6 +148,7 @@ public class Snake {
return String.format("{'id':%d,'body':[%s]}", Integer.valueOf(this.id),
sb.toString());
}
}
public int getId() {
return this.id;
......
......@@ -33,31 +33,37 @@ import org.apache.juli.logging.LogFactory;
*/
public class SnakeTimer {
private static final Log log = LogFactory.getLog(SnakeTimer.class);
private static final long TICK_DELAY = 100;
private static Timer gameTimer = null;
private static final Object MONITOR = new Object();
private static final long TICK_DELAY = 100;
private static final Log log = LogFactory.getLog(SnakeTimer.class);
private static final ConcurrentHashMap<Integer, Snake> snakes = new ConcurrentHashMap<Integer, Snake>();
public static synchronized void addSnake(Snake snake) {
private static Timer gameTimer = null;
public static void addSnake(Snake snake) {
synchronized (MONITOR) {
if (snakes.isEmpty()) {
startTimer();
}
snakes.put(Integer.valueOf(snake.getId()), snake);
}
}
public static Collection<Snake> getSnakes() {
return Collections.unmodifiableCollection(snakes.values());
}
public static synchronized void removeSnake(Snake snake) {
public static void removeSnake(Snake snake) {
synchronized (MONITOR) {
snakes.remove(Integer.valueOf(snake.getId()));
if (snakes.isEmpty()) {
stopTimer();
}
}
}
public static void tick() throws Exception {
StringBuilder sb = new StringBuilder();
......
......@@ -28,14 +28,21 @@ public class Snake {
private static final int DEFAULT_LENGTH = 5;
private final Deque<Location> tail = new ArrayDeque<Location>();
private final Object monitor = new Object();
private final int id;
private final WebSocketSession session;
private final String hexColor;
private Direction direction;
private int length = DEFAULT_LENGTH;
private Location head;
private final Deque<Location> tail = new ArrayDeque<Location>();
private final String hexColor;
public Snake(int id, WebSocketSession session) {
this.id = id;
......@@ -51,21 +58,26 @@ public class Snake {
this.length = DEFAULT_LENGTH;
}
private synchronized void kill() throws Exception {
private void kill() throws Exception {
synchronized (this.monitor) {
resetState();
sendMessage("{'type': 'dead'}");
}
}
private synchronized void reward() throws Exception {
private void reward() throws Exception {
synchronized (this.monitor) {
this.length++;
sendMessage("{'type': 'kill'}");
}
}
protected void sendMessage(String msg) throws Exception {
this.session.sendMessage(new TextMessage(msg));
}
public synchronized void update(Collection<Snake> snakes) throws Exception {
public void update(Collection<Snake> snakes) throws Exception {
synchronized (this.monitor) {
Location nextLocation = this.head.getAdjacentLocation(this.direction);
if (nextLocation.x >= SnakeUtils.PLAYFIELD_WIDTH) {
nextLocation.x = 0;
......@@ -89,6 +101,7 @@ public class Snake {
handleCollisions(snakes);
}
}
private void handleCollisions(Collection<Snake> snakes) throws Exception {
for (Snake snake : snakes) {
......@@ -104,19 +117,26 @@ public class Snake {
}
}
public synchronized Location getHead() {
public Location getHead() {
synchronized (this.monitor) {
return this.head;
}
}
public synchronized Collection<Location> getTail() {
public Collection<Location> getTail() {
synchronized (this.monitor) {
return this.tail;
}
}
public synchronized void setDirection(Direction direction) {
public void setDirection(Direction direction) {
synchronized (this.monitor) {
this.direction = direction;
}
}
public synchronized String getLocationsJson() {
public String getLocationsJson() {
synchronized (this.monitor) {
StringBuilder sb = new StringBuilder();
sb.append(String.format("{x: %d, y: %d}", Integer.valueOf(this.head.x),
Integer.valueOf(this.head.y)));
......@@ -128,6 +148,7 @@ public class Snake {
return String.format("{'id':%d,'body':[%s]}", Integer.valueOf(this.id),
sb.toString());
}
}
public int getId() {
return this.id;
......
......@@ -33,31 +33,37 @@ import org.slf4j.LoggerFactory;
*/
public class SnakeTimer {
private static final Logger log = LoggerFactory.getLogger(SnakeTimer.class);
private static final long TICK_DELAY = 100;
private static Timer gameTimer = null;
private static final Object MONITOR = new Object();
private static final long TICK_DELAY = 100;
private static final Logger log = LoggerFactory.getLogger(SnakeTimer.class);
private static final ConcurrentHashMap<Integer, Snake> snakes = new ConcurrentHashMap<Integer, Snake>();
public static synchronized void addSnake(Snake snake) {
private static Timer gameTimer = null;
public static void addSnake(Snake snake) {
synchronized (MONITOR) {
if (snakes.isEmpty()) {
startTimer();
}
snakes.put(Integer.valueOf(snake.getId()), snake);
}
}
public static Collection<Snake> getSnakes() {
return Collections.unmodifiableCollection(snakes.values());
}
public static synchronized void removeSnake(Snake snake) {
public static void removeSnake(Snake snake) {
synchronized (MONITOR) {
snakes.remove(Integer.valueOf(snake.getId()));
if (snakes.isEmpty()) {
stopTimer();
}
}
}
public static void tick() throws Exception {
StringBuilder sb = new StringBuilder();
......
......@@ -89,6 +89,8 @@ class MockitoAopProxyTargetInterceptor implements MethodInterceptor {
private static class Verification {
private final Object monitor = new Object();
private final MockingProgress progress;
Verification(Object target) {
......@@ -101,7 +103,8 @@ class MockitoAopProxyTargetInterceptor implements MethodInterceptor {
this.progress = (MockingProgress) ReflectionUtils.getField(field, container);
}
public synchronized boolean isVerifying() {
public boolean isVerifying() {
synchronized (this.monitor) {
VerificationMode mode = this.progress.pullVerificationMode();
if (mode != null) {
this.progress.verificationStarted(mode);
......@@ -109,8 +112,10 @@ class MockitoAopProxyTargetInterceptor implements MethodInterceptor {
}
return false;
}
}
public synchronized void replaceVerifyMock(Object source, Object target) {
public void replaceVerifyMock(Object source, Object target) {
synchronized (this.monitor) {
VerificationMode mode = this.progress.pullVerificationMode();
if (mode != null) {
if (mode instanceof MockAwareVerificationMode) {
......@@ -122,6 +127,7 @@ class MockitoAopProxyTargetInterceptor implements MethodInterceptor {
this.progress.verificationStarted(mode);
}
}
}
}
......
......@@ -426,6 +426,8 @@ public abstract class AbstractRunMojo extends AbstractDependencyFilterMojo {
*/
class IsolatedThreadGroup extends ThreadGroup {
private final Object monitor = new Object();
private Throwable exception;
IsolatedThreadGroup(String name) {
......@@ -435,18 +437,21 @@ public abstract class AbstractRunMojo extends AbstractDependencyFilterMojo {
@Override
public void uncaughtException(Thread thread, Throwable ex) {
if (!(ex instanceof ThreadDeath)) {
synchronized (this) {
synchronized (this.monitor) {
this.exception = (this.exception == null ? ex : this.exception);
}
getLog().warn(ex);
}
}
public synchronized void rethrowUncaughtException()
throws MojoExecutionException {
public void rethrowUncaughtException() throws MojoExecutionException {
synchronized (this.monitor) {
if (this.exception != null) {
throw new MojoExecutionException("An exception occurred while running. "
+ this.exception.getMessage(), this.exception);
throw new MojoExecutionException(
"An exception occurred while running. "
+ this.exception.getMessage(),
this.exception);
}
}
}
......
......@@ -51,6 +51,8 @@ public class JettyEmbeddedServletContainer implements EmbeddedServletContainer {
private static final Log logger = LogFactory
.getLog(JettyEmbeddedServletContainer.class);
private final Object monitor = new Object();
private final Server server;
private final boolean autoStart;
......@@ -77,7 +79,8 @@ public class JettyEmbeddedServletContainer implements EmbeddedServletContainer {
initialize();
}
private synchronized void initialize() {
private void initialize() {
synchronized (this.monitor) {
try {
// Cache and clear the connectors to prevent requests being handled before
// the application context is ready
......@@ -95,6 +98,7 @@ public class JettyEmbeddedServletContainer implements EmbeddedServletContainer {
"Unable to start embedded Jetty servlet container", ex);
}
}
}
private void stopSilently() {
try {
......@@ -191,7 +195,8 @@ public class JettyEmbeddedServletContainer implements EmbeddedServletContainer {
}
@Override
public synchronized void stop() {
public void stop() {
synchronized (this.monitor) {
try {
this.server.stop();
}
......@@ -203,6 +208,7 @@ public class JettyEmbeddedServletContainer implements EmbeddedServletContainer {
"Unable to stop embedded Jetty servlet container", ex);
}
}
}
@Override
public int getPort() {
......
......@@ -53,12 +53,14 @@ public class TomcatEmbeddedServletContainer implements EmbeddedServletContainer
private static final Log logger = LogFactory
.getLog(TomcatEmbeddedServletContainer.class);
private static AtomicInteger containerCounter = new AtomicInteger(-1);
private static final AtomicInteger containerCounter = new AtomicInteger(-1);
private final Tomcat tomcat;
private final Object monitor = new Object();
private final Map<Service, Connector[]> serviceConnectors = new HashMap<Service, Connector[]>();
private final Tomcat tomcat;
private final boolean autoStart;
/**
......@@ -81,9 +83,10 @@ public class TomcatEmbeddedServletContainer implements EmbeddedServletContainer
initialize();
}
private synchronized void initialize() throws EmbeddedServletContainerException {
private void initialize() throws EmbeddedServletContainerException {
TomcatEmbeddedServletContainer.logger
.info("Tomcat initialized with port(s): " + getPortsDescription(false));
synchronized (this.monitor) {
try {
addInstanceIdToEngineName();
......@@ -110,8 +113,9 @@ public class TomcatEmbeddedServletContainer implements EmbeddedServletContainer
startDaemonAwaitThread();
}
catch (Exception ex) {
throw new EmbeddedServletContainerException("Unable to start embedded Tomcat",
ex);
throw new EmbeddedServletContainerException(
"Unable to start embedded Tomcat", ex);
}
}
}
......@@ -266,7 +270,8 @@ public class TomcatEmbeddedServletContainer implements EmbeddedServletContainer
}
@Override
public synchronized void stop() throws EmbeddedServletContainerException {
public void stop() throws EmbeddedServletContainerException {
synchronized (this.monitor) {
try {
try {
stopTomcat();
......@@ -277,13 +282,14 @@ public class TomcatEmbeddedServletContainer implements EmbeddedServletContainer
}
}
catch (Exception ex) {
throw new EmbeddedServletContainerException("Unable to stop embedded Tomcat",
ex);
throw new EmbeddedServletContainerException(
"Unable to stop embedded Tomcat", ex);
}
finally {
containerCounter.decrementAndGet();
}
}
}
private String getPortsDescription(boolean localPort) {
StringBuilder ports = new StringBuilder();
......
......@@ -70,6 +70,8 @@ public class UndertowEmbeddedServletContainer implements EmbeddedServletContaine
private static final Log logger = LogFactory
.getLog(UndertowEmbeddedServletContainer.class);
private final Object monitor = new Object();
private final Builder builder;
private final DeploymentManager manager;
......@@ -197,7 +199,8 @@ public class UndertowEmbeddedServletContainer implements EmbeddedServletContaine
}
@Override
public synchronized void start() throws EmbeddedServletContainerException {
public void start() throws EmbeddedServletContainerException {
synchronized (this.monitor) {
try {
if (!this.autoStart) {
return;
......@@ -224,6 +227,7 @@ public class UndertowEmbeddedServletContainer implements EmbeddedServletContaine
"Unable to start embedded Undertow", ex);
}
}
}
private BindException findBindException(Exception ex) {
Throwable candidate = ex;
......@@ -356,7 +360,8 @@ public class UndertowEmbeddedServletContainer implements EmbeddedServletContaine
}
@Override
public synchronized void stop() throws EmbeddedServletContainerException {
public void stop() throws EmbeddedServletContainerException {
synchronized (this.monitor) {
if (this.started) {
try {
this.started = false;
......@@ -369,6 +374,7 @@ public class UndertowEmbeddedServletContainer implements EmbeddedServletContaine
}
}
}
}
@Override
public int getPort() {
......
/*
* Copyright 2012-2015 the original author or authors.
* Copyright 2012-2016 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
......@@ -46,7 +46,7 @@ import org.springframework.util.StringUtils;
public class PoolingConnectionFactoryBean extends PoolingConnectionFactory
implements BeanNameAware, InitializingBean, DisposableBean {
private static ThreadLocal<PoolingConnectionFactoryBean> source = new ThreadLocal<PoolingConnectionFactoryBean>();
private static final ThreadLocal<PoolingConnectionFactoryBean> source = new ThreadLocal<PoolingConnectionFactoryBean>();
private String beanName;
......
/*
* Copyright 2012-2015 the original author or authors.
* Copyright 2012-2016 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
......@@ -50,7 +50,7 @@ import org.springframework.util.StringUtils;
public class PoolingDataSourceBean extends PoolingDataSource
implements BeanNameAware, InitializingBean {
private static ThreadLocal<PoolingDataSourceBean> source = new ThreadLocal<PoolingDataSourceBean>();
private static final ThreadLocal<PoolingDataSourceBean> source = new ThreadLocal<PoolingDataSourceBean>();
private XADataSource dataSource;
......
......@@ -51,7 +51,7 @@ public class AtomikosDataSourceBeanTests {
}
@Override
public synchronized void close() {
public void close() {
}
}
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment