mirror of
https://github.com/spring-projects/spring-boot.git
synced 2024-08-29 03:06:45 +08:00
parent
02a7c22f40
commit
1a8b8ce26e
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2012-2023 the original author or authors.
|
||||
* Copyright 2012-2022 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.
|
||||
@ -22,8 +22,6 @@ import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.locks.Lock;
|
||||
import java.util.concurrent.locks.ReentrantLock;
|
||||
|
||||
import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.core.env.Environment;
|
||||
@ -54,13 +52,7 @@ public class TemplateAvailabilityProviders {
|
||||
private final Map<String, TemplateAvailabilityProvider> resolved = new ConcurrentHashMap<>(CACHE_LIMIT);
|
||||
|
||||
/**
|
||||
* Guards access to {@link #cache}.
|
||||
*/
|
||||
private final Lock cacheLock = new ReentrantLock();
|
||||
|
||||
/**
|
||||
* Map from view name resolve template view, protected by {@link #cacheLock} when
|
||||
* accessed.
|
||||
* Map from view name resolve template view, synchronized when accessed.
|
||||
*/
|
||||
private final Map<String, TemplateAvailabilityProvider> cache = new LinkedHashMap<>(CACHE_LIMIT, 0.75f, true) {
|
||||
|
||||
@ -141,16 +133,12 @@ public class TemplateAvailabilityProviders {
|
||||
}
|
||||
TemplateAvailabilityProvider provider = this.resolved.get(view);
|
||||
if (provider == null) {
|
||||
this.cacheLock.lock();
|
||||
try {
|
||||
synchronized (this.cache) {
|
||||
provider = findProvider(view, environment, classLoader, resourceLoader);
|
||||
provider = (provider != null) ? provider : NONE;
|
||||
this.resolved.put(view, provider);
|
||||
this.cache.put(view, provider);
|
||||
}
|
||||
finally {
|
||||
this.cacheLock.unlock();
|
||||
}
|
||||
}
|
||||
return (provider != NONE) ? provider : null;
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2012-2023 the original author or authors.
|
||||
* Copyright 2012-2022 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.
|
||||
@ -158,8 +158,10 @@ public class FileSystemWatcher {
|
||||
}
|
||||
|
||||
private void checkNotStarted() {
|
||||
synchronized (this.monitor) {
|
||||
Assert.state(this.watchThread == null, "FileSystemWatcher already started");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Start monitoring the source directory for changes.
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2012-2023 the original author or authors.
|
||||
* Copyright 2012-2019 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.
|
||||
@ -29,8 +29,6 @@ import java.util.concurrent.Executors;
|
||||
import java.util.concurrent.ThreadFactory;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
import java.util.concurrent.locks.Lock;
|
||||
import java.util.concurrent.locks.ReentrantLock;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
@ -59,12 +57,7 @@ public class LiveReloadServer {
|
||||
|
||||
private final List<Connection> connections = new ArrayList<>();
|
||||
|
||||
/**
|
||||
* Guards access to {@link #connections}.
|
||||
*/
|
||||
private final Lock connectionsLock = new ReentrantLock();
|
||||
|
||||
private final Lock lock = new ReentrantLock();
|
||||
private final Object monitor = new Object();
|
||||
|
||||
private final int port;
|
||||
|
||||
@ -115,8 +108,7 @@ public class LiveReloadServer {
|
||||
* @throws IOException in case of I/O errors
|
||||
*/
|
||||
public int start() throws IOException {
|
||||
this.lock.lock();
|
||||
try {
|
||||
synchronized (this.monitor) {
|
||||
Assert.state(!isStarted(), "Server already started");
|
||||
logger.debug(LogMessage.format("Starting live reload server on port %s", this.port));
|
||||
this.serverSocket = new ServerSocket(this.port);
|
||||
@ -127,9 +119,6 @@ public class LiveReloadServer {
|
||||
this.listenThread.start();
|
||||
return localPort;
|
||||
}
|
||||
finally {
|
||||
this.lock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@ -137,13 +126,9 @@ public class LiveReloadServer {
|
||||
* @return {@code true} if the server is running
|
||||
*/
|
||||
public boolean isStarted() {
|
||||
this.lock.lock();
|
||||
try {
|
||||
synchronized (this.monitor) {
|
||||
return this.listenThread != null;
|
||||
}
|
||||
finally {
|
||||
this.lock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@ -178,8 +163,7 @@ public class LiveReloadServer {
|
||||
* @throws IOException in case of I/O errors
|
||||
*/
|
||||
public void stop() throws IOException {
|
||||
this.lock.lock();
|
||||
try {
|
||||
synchronized (this.monitor) {
|
||||
if (this.listenThread != null) {
|
||||
closeAllConnections();
|
||||
try {
|
||||
@ -200,31 +184,22 @@ public class LiveReloadServer {
|
||||
this.serverSocket = null;
|
||||
}
|
||||
}
|
||||
finally {
|
||||
this.lock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
private void closeAllConnections() throws IOException {
|
||||
this.connectionsLock.lock();
|
||||
try {
|
||||
synchronized (this.connections) {
|
||||
for (Connection connection : this.connections) {
|
||||
connection.close();
|
||||
}
|
||||
}
|
||||
finally {
|
||||
this.connectionsLock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Trigger livereload of all connected clients.
|
||||
*/
|
||||
public void triggerReload() {
|
||||
this.lock.lock();
|
||||
try {
|
||||
this.connectionsLock.lock();
|
||||
try {
|
||||
synchronized (this.monitor) {
|
||||
synchronized (this.connections) {
|
||||
for (Connection connection : this.connections) {
|
||||
try {
|
||||
connection.triggerReload();
|
||||
@ -234,33 +209,19 @@ public class LiveReloadServer {
|
||||
}
|
||||
}
|
||||
}
|
||||
finally {
|
||||
this.connectionsLock.unlock();
|
||||
}
|
||||
}
|
||||
finally {
|
||||
this.lock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
private void addConnection(Connection connection) {
|
||||
this.connectionsLock.lock();
|
||||
try {
|
||||
synchronized (this.connections) {
|
||||
this.connections.add(connection);
|
||||
}
|
||||
finally {
|
||||
this.connectionsLock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
private void removeConnection(Connection connection) {
|
||||
this.connectionsLock.lock();
|
||||
try {
|
||||
synchronized (this.connections) {
|
||||
this.connections.remove(connection);
|
||||
}
|
||||
finally {
|
||||
this.connectionsLock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2012-2023 the original author or authors.
|
||||
* Copyright 2012-2022 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.
|
||||
@ -22,6 +22,7 @@ import java.lang.reflect.Field;
|
||||
import java.net.URL;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.HashMap;
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
@ -29,7 +30,6 @@ import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.BlockingDeque;
|
||||
import java.util.concurrent.Callable;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.CopyOnWriteArrayList;
|
||||
import java.util.concurrent.LinkedBlockingDeque;
|
||||
import java.util.concurrent.ThreadFactory;
|
||||
@ -92,7 +92,7 @@ public class Restarter {
|
||||
|
||||
private final ClassLoaderFiles classLoaderFiles = new ClassLoaderFiles();
|
||||
|
||||
private final Map<String, Object> attributes = new ConcurrentHashMap<>();
|
||||
private final Map<String, Object> attributes = new HashMap<>();
|
||||
|
||||
private final BlockingDeque<LeakSafeThread> leakSafeThreads = new LinkedBlockingDeque<>();
|
||||
|
||||
@ -440,12 +440,19 @@ public class Restarter {
|
||||
}
|
||||
|
||||
public Object getOrAddAttribute(String name, final ObjectFactory<?> objectFactory) {
|
||||
return this.attributes.computeIfAbsent(name, (ignore) -> objectFactory.getObject());
|
||||
synchronized (this.attributes) {
|
||||
if (!this.attributes.containsKey(name)) {
|
||||
this.attributes.put(name, objectFactory.getObject());
|
||||
}
|
||||
return this.attributes.get(name);
|
||||
}
|
||||
}
|
||||
|
||||
public Object removeAttribute(String name) {
|
||||
synchronized (this.attributes) {
|
||||
return this.attributes.remove(name);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the initial set of URLs as configured by the {@link RestartInitializer}.
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2012-2023 the original author or authors.
|
||||
* Copyright 2012-2019 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.
|
||||
@ -25,8 +25,6 @@ import java.nio.channels.AsynchronousCloseException;
|
||||
import java.nio.channels.ServerSocketChannel;
|
||||
import java.nio.channels.SocketChannel;
|
||||
import java.nio.channels.WritableByteChannel;
|
||||
import java.util.concurrent.locks.Lock;
|
||||
import java.util.concurrent.locks.ReentrantLock;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
@ -51,7 +49,7 @@ public class TunnelClient implements SmartInitializingSingleton {
|
||||
|
||||
private final TunnelClientListeners listeners = new TunnelClientListeners();
|
||||
|
||||
private final Lock lock = new ReentrantLock();
|
||||
private final Object monitor = new Object();
|
||||
|
||||
private final int listenPort;
|
||||
|
||||
@ -68,8 +66,7 @@ public class TunnelClient implements SmartInitializingSingleton {
|
||||
|
||||
@Override
|
||||
public void afterSingletonsInstantiated() {
|
||||
this.lock.lock();
|
||||
try {
|
||||
synchronized (this.monitor) {
|
||||
if (this.serverThread == null) {
|
||||
try {
|
||||
start();
|
||||
@ -79,9 +76,6 @@ public class TunnelClient implements SmartInitializingSingleton {
|
||||
}
|
||||
}
|
||||
}
|
||||
finally {
|
||||
this.lock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@ -90,8 +84,7 @@ public class TunnelClient implements SmartInitializingSingleton {
|
||||
* @throws IOException in case of I/O errors
|
||||
*/
|
||||
public int start() throws IOException {
|
||||
this.lock.lock();
|
||||
try {
|
||||
synchronized (this.monitor) {
|
||||
Assert.state(this.serverThread == null, "Server already started");
|
||||
ServerSocketChannel serverSocketChannel = ServerSocketChannel.open();
|
||||
serverSocketChannel.socket().bind(new InetSocketAddress(this.listenPort));
|
||||
@ -101,9 +94,6 @@ public class TunnelClient implements SmartInitializingSingleton {
|
||||
this.serverThread.start();
|
||||
return port;
|
||||
}
|
||||
finally {
|
||||
this.lock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@ -111,8 +101,7 @@ public class TunnelClient implements SmartInitializingSingleton {
|
||||
* @throws IOException in case of I/O errors
|
||||
*/
|
||||
public void stop() throws IOException {
|
||||
this.lock.lock();
|
||||
try {
|
||||
synchronized (this.monitor) {
|
||||
if (this.serverThread != null) {
|
||||
this.serverThread.close();
|
||||
try {
|
||||
@ -124,19 +113,12 @@ public class TunnelClient implements SmartInitializingSingleton {
|
||||
this.serverThread = null;
|
||||
}
|
||||
}
|
||||
finally {
|
||||
this.lock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
protected final ServerThread getServerThread() {
|
||||
this.lock.lock();
|
||||
try {
|
||||
synchronized (this.monitor) {
|
||||
return this.serverThread;
|
||||
}
|
||||
finally {
|
||||
this.lock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
public void addListener(TunnelClientListener listener) {
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2012-2023 the original author or authors.
|
||||
* Copyright 2012-2019 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.
|
||||
@ -20,8 +20,6 @@ import java.io.IOException;
|
||||
import java.nio.channels.WritableByteChannel;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.locks.Lock;
|
||||
import java.util.concurrent.locks.ReentrantLock;
|
||||
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
@ -38,7 +36,7 @@ public class HttpTunnelPayloadForwarder {
|
||||
|
||||
private final Map<Long, HttpTunnelPayload> queue = new HashMap<>();
|
||||
|
||||
private final Lock lock = new ReentrantLock();
|
||||
private final Object monitor = new Object();
|
||||
|
||||
private final WritableByteChannel targetChannel;
|
||||
|
||||
@ -54,8 +52,7 @@ public class HttpTunnelPayloadForwarder {
|
||||
}
|
||||
|
||||
public void forward(HttpTunnelPayload payload) throws IOException {
|
||||
this.lock.lock();
|
||||
try {
|
||||
synchronized (this.monitor) {
|
||||
long seq = payload.getSequence();
|
||||
if (this.lastRequestSeq != seq - 1) {
|
||||
Assert.state(this.queue.size() < MAXIMUM_QUEUE_SIZE, "Too many messages queued");
|
||||
@ -70,9 +67,6 @@ public class HttpTunnelPayloadForwarder {
|
||||
forward(queuedItem);
|
||||
}
|
||||
}
|
||||
finally {
|
||||
this.lock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2012-2023 the original author or authors.
|
||||
* Copyright 2012-2022 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.
|
||||
@ -25,9 +25,6 @@ import java.util.Deque;
|
||||
import java.util.Iterator;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.concurrent.atomic.AtomicLong;
|
||||
import java.util.concurrent.locks.Condition;
|
||||
import java.util.concurrent.locks.Lock;
|
||||
import java.util.concurrent.locks.ReentrantLock;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
@ -125,12 +122,7 @@ public class HttpTunnelServer {
|
||||
|
||||
private long disconnectTimeout = DEFAULT_DISCONNECT_TIMEOUT;
|
||||
|
||||
/**
|
||||
* Guards access to {@link #serverThread}.
|
||||
*/
|
||||
private final Lock serverThreadLock = new ReentrantLock();
|
||||
|
||||
private ServerThread serverThread;
|
||||
private volatile ServerThread serverThread;
|
||||
|
||||
/**
|
||||
* Creates a new {@link HttpTunnelServer} instance.
|
||||
@ -172,8 +164,7 @@ public class HttpTunnelServer {
|
||||
* @throws IOException in case of I/O errors
|
||||
*/
|
||||
protected ServerThread getServerThread() throws IOException {
|
||||
this.serverThreadLock.lock();
|
||||
try {
|
||||
synchronized (this) {
|
||||
if (this.serverThread == null) {
|
||||
ByteChannel channel = this.serverConnection.open(this.longPollTimeout);
|
||||
this.serverThread = new ServerThread(channel);
|
||||
@ -181,22 +172,15 @@ public class HttpTunnelServer {
|
||||
}
|
||||
return this.serverThread;
|
||||
}
|
||||
finally {
|
||||
this.serverThreadLock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when the server thread exits.
|
||||
*/
|
||||
void clearServerThread() {
|
||||
this.serverThreadLock.lock();
|
||||
try {
|
||||
synchronized (this) {
|
||||
this.serverThread = null;
|
||||
}
|
||||
finally {
|
||||
this.serverThreadLock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@ -226,13 +210,6 @@ public class HttpTunnelServer {
|
||||
|
||||
private final Deque<HttpConnection> httpConnections;
|
||||
|
||||
/**
|
||||
* Guards access to {@link #httpConnections}.
|
||||
*/
|
||||
private final Lock httpConnectionsLock = new ReentrantLock();
|
||||
|
||||
private final Condition httpConnectionsCondition = this.httpConnectionsLock.newCondition();
|
||||
|
||||
private final HttpTunnelPayloadForwarder payloadForwarder;
|
||||
|
||||
private boolean closed;
|
||||
@ -270,8 +247,7 @@ public class HttpTunnelServer {
|
||||
while (this.targetServer.isOpen()) {
|
||||
closeStaleHttpConnections();
|
||||
ByteBuffer data = HttpTunnelPayload.getPayloadData(this.targetServer);
|
||||
this.httpConnectionsLock.lock();
|
||||
try {
|
||||
synchronized (this.httpConnections) {
|
||||
if (data != null) {
|
||||
HttpTunnelPayload payload = new HttpTunnelPayload(this.responseSeq.incrementAndGet(), data);
|
||||
payload.logIncoming();
|
||||
@ -279,20 +255,15 @@ public class HttpTunnelServer {
|
||||
connection.respond(payload);
|
||||
}
|
||||
}
|
||||
finally {
|
||||
this.httpConnectionsLock.unlock();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private HttpConnection getOrWaitForHttpConnection() {
|
||||
this.httpConnectionsLock.lock();
|
||||
try {
|
||||
synchronized (this.httpConnections) {
|
||||
HttpConnection httpConnection = this.httpConnections.pollFirst();
|
||||
while (httpConnection == null) {
|
||||
try {
|
||||
this.httpConnectionsCondition.await(HttpTunnelServer.this.longPollTimeout,
|
||||
TimeUnit.MILLISECONDS);
|
||||
this.httpConnections.wait(HttpTunnelServer.this.longPollTimeout);
|
||||
}
|
||||
catch (InterruptedException ex) {
|
||||
Thread.currentThread().interrupt();
|
||||
@ -302,14 +273,10 @@ public class HttpTunnelServer {
|
||||
}
|
||||
return httpConnection;
|
||||
}
|
||||
finally {
|
||||
this.httpConnectionsLock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
private void closeStaleHttpConnections() throws IOException {
|
||||
this.httpConnectionsLock.lock();
|
||||
try {
|
||||
synchronized (this.httpConnections) {
|
||||
checkNotDisconnected();
|
||||
Iterator<HttpConnection> iterator = this.httpConnections.iterator();
|
||||
while (iterator.hasNext()) {
|
||||
@ -320,9 +287,6 @@ public class HttpTunnelServer {
|
||||
}
|
||||
}
|
||||
}
|
||||
finally {
|
||||
this.httpConnectionsLock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
private void checkNotDisconnected() {
|
||||
@ -334,8 +298,7 @@ public class HttpTunnelServer {
|
||||
}
|
||||
|
||||
private void closeHttpConnections() {
|
||||
this.httpConnectionsLock.lock();
|
||||
try {
|
||||
synchronized (this.httpConnections) {
|
||||
while (!this.httpConnections.isEmpty()) {
|
||||
try {
|
||||
this.httpConnections.removeFirst().respond(HttpStatus.GONE);
|
||||
@ -345,9 +308,6 @@ public class HttpTunnelServer {
|
||||
}
|
||||
}
|
||||
}
|
||||
finally {
|
||||
this.httpConnectionsLock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
private void closeTargetServer() {
|
||||
@ -368,17 +328,13 @@ public class HttpTunnelServer {
|
||||
if (this.closed) {
|
||||
httpConnection.respond(HttpStatus.GONE);
|
||||
}
|
||||
this.httpConnectionsLock.lock();
|
||||
try {
|
||||
synchronized (this.httpConnections) {
|
||||
while (this.httpConnections.size() > 1) {
|
||||
this.httpConnections.removeFirst().respond(HttpStatus.TOO_MANY_REQUESTS);
|
||||
}
|
||||
this.lastHttpRequestTime = System.currentTimeMillis();
|
||||
this.httpConnections.addLast(httpConnection);
|
||||
this.httpConnectionsCondition.signal();
|
||||
}
|
||||
finally {
|
||||
this.httpConnectionsLock.unlock();
|
||||
this.httpConnections.notify();
|
||||
}
|
||||
forwardToTargetServer(httpConnection);
|
||||
}
|
||||
@ -412,10 +368,6 @@ public class HttpTunnelServer {
|
||||
|
||||
private volatile boolean complete = false;
|
||||
|
||||
private final Lock lock = new ReentrantLock();
|
||||
|
||||
private final Condition lockCondition = this.lock.newCondition();
|
||||
|
||||
public HttpConnection(ServerHttpRequest request, ServerHttpResponse response) {
|
||||
this.createTime = System.currentTimeMillis();
|
||||
this.request = request;
|
||||
@ -474,12 +426,8 @@ public class HttpTunnelServer {
|
||||
if (this.async == null) {
|
||||
while (!this.complete) {
|
||||
try {
|
||||
this.lock.lock();
|
||||
try {
|
||||
this.lockCondition.await(1, TimeUnit.SECONDS);
|
||||
}
|
||||
finally {
|
||||
this.lock.unlock();
|
||||
synchronized (this) {
|
||||
wait(1000);
|
||||
}
|
||||
}
|
||||
catch (InterruptedException ex) {
|
||||
@ -528,13 +476,9 @@ public class HttpTunnelServer {
|
||||
this.async.complete();
|
||||
}
|
||||
else {
|
||||
this.lock.lock();
|
||||
try {
|
||||
synchronized (this) {
|
||||
this.complete = true;
|
||||
this.lockCondition.signalAll();
|
||||
}
|
||||
finally {
|
||||
this.lock.unlock();
|
||||
notifyAll();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2012-2023 the original author or authors.
|
||||
* Copyright 2012-2022 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.
|
||||
@ -18,8 +18,6 @@ package org.springframework.boot.test.autoconfigure.web.servlet;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.locks.Lock;
|
||||
import java.util.concurrent.locks.ReentrantLock;
|
||||
|
||||
import org.openqa.selenium.WebDriver;
|
||||
|
||||
@ -54,17 +52,11 @@ public class WebDriverScope implements Scope {
|
||||
private static final String[] BEAN_CLASSES = { WEB_DRIVER_CLASS,
|
||||
"org.springframework.test.web.servlet.htmlunit.webdriver.MockMvcHtmlUnitDriverBuilder" };
|
||||
|
||||
/**
|
||||
* Guards access to {@link #instances}.
|
||||
*/
|
||||
private final Lock instancesLock = new ReentrantLock();
|
||||
|
||||
private final Map<String, Object> instances = new HashMap<>();
|
||||
|
||||
@Override
|
||||
public Object get(String name, ObjectFactory<?> objectFactory) {
|
||||
this.instancesLock.lock();
|
||||
try {
|
||||
synchronized (this.instances) {
|
||||
Object instance = this.instances.get(name);
|
||||
if (instance == null) {
|
||||
instance = objectFactory.getObject();
|
||||
@ -72,20 +64,13 @@ public class WebDriverScope implements Scope {
|
||||
}
|
||||
return instance;
|
||||
}
|
||||
finally {
|
||||
this.instancesLock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object remove(String name) {
|
||||
this.instancesLock.lock();
|
||||
try {
|
||||
synchronized (this.instances) {
|
||||
return this.instances.remove(name);
|
||||
}
|
||||
finally {
|
||||
this.instancesLock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -108,8 +93,7 @@ public class WebDriverScope implements Scope {
|
||||
*/
|
||||
boolean reset() {
|
||||
boolean reset = false;
|
||||
this.instancesLock.lock();
|
||||
try {
|
||||
synchronized (this.instances) {
|
||||
for (Object instance : this.instances.values()) {
|
||||
reset = true;
|
||||
if (instance instanceof WebDriver webDriver) {
|
||||
@ -118,9 +102,6 @@ public class WebDriverScope implements Scope {
|
||||
}
|
||||
this.instances.clear();
|
||||
}
|
||||
finally {
|
||||
this.instancesLock.unlock();
|
||||
}
|
||||
return reset;
|
||||
}
|
||||
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2012-2023 the original author or authors.
|
||||
* Copyright 2012-2020 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.
|
||||
@ -21,8 +21,6 @@ import java.io.IOException;
|
||||
import java.net.MalformedURLException;
|
||||
import java.net.URL;
|
||||
import java.nio.file.Files;
|
||||
import java.util.concurrent.locks.Lock;
|
||||
import java.util.concurrent.locks.ReentrantLock;
|
||||
|
||||
import org.springframework.core.io.FileSystemResourceLoader;
|
||||
import org.springframework.core.io.Resource;
|
||||
@ -46,11 +44,6 @@ public class SpringBootMockServletContext extends MockServletContext {
|
||||
|
||||
private File emptyRootDirectory;
|
||||
|
||||
/**
|
||||
* Guards access to {@link #emptyRootDirectory}.
|
||||
*/
|
||||
private final Lock emptyRootDirectoryLock = new ReentrantLock();
|
||||
|
||||
public SpringBootMockServletContext(String resourceBasePath) {
|
||||
this(resourceBasePath, new FileSystemResourceLoader());
|
||||
}
|
||||
@ -98,21 +91,19 @@ public class SpringBootMockServletContext extends MockServletContext {
|
||||
if (resource == null && "/".equals(path)) {
|
||||
// Liquibase assumes that "/" always exists, if we don't have a directory
|
||||
// use a temporary location.
|
||||
this.emptyRootDirectoryLock.lock();
|
||||
try {
|
||||
if (this.emptyRootDirectory == null) {
|
||||
synchronized (this) {
|
||||
File tempDirectory = Files.createTempDirectory("spr-servlet").toFile();
|
||||
tempDirectory.deleteOnExit();
|
||||
this.emptyRootDirectory = tempDirectory;
|
||||
}
|
||||
}
|
||||
return this.emptyRootDirectory.toURI().toURL();
|
||||
}
|
||||
catch (IOException ex) {
|
||||
// Ignore
|
||||
}
|
||||
finally {
|
||||
this.emptyRootDirectoryLock.unlock();
|
||||
}
|
||||
}
|
||||
return resource;
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2012-2023 the original author or authors.
|
||||
* Copyright 2012-2022 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.
|
||||
@ -22,8 +22,6 @@ import java.io.FileNotFoundException;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.RandomAccessFile;
|
||||
import java.util.concurrent.locks.Lock;
|
||||
import java.util.concurrent.locks.ReentrantLock;
|
||||
|
||||
/**
|
||||
* {@link RandomAccessData} implementation backed by a {@link RandomAccessFile}.
|
||||
@ -211,7 +209,7 @@ public class RandomAccessDataFile implements RandomAccessData {
|
||||
|
||||
private static final class FileAccess {
|
||||
|
||||
private final Lock lock = new ReentrantLock();
|
||||
private final Object monitor = new Object();
|
||||
|
||||
private final File file;
|
||||
|
||||
@ -223,15 +221,11 @@ public class RandomAccessDataFile implements RandomAccessData {
|
||||
}
|
||||
|
||||
private int read(byte[] bytes, long position, int offset, int length) throws IOException {
|
||||
this.lock.lock();
|
||||
try {
|
||||
synchronized (this.monitor) {
|
||||
openIfNecessary();
|
||||
this.randomAccessFile.seek(position);
|
||||
return this.randomAccessFile.read(bytes, offset, length);
|
||||
}
|
||||
finally {
|
||||
this.lock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
private void openIfNecessary() {
|
||||
@ -247,28 +241,20 @@ public class RandomAccessDataFile implements RandomAccessData {
|
||||
}
|
||||
|
||||
private void close() throws IOException {
|
||||
this.lock.lock();
|
||||
try {
|
||||
synchronized (this.monitor) {
|
||||
if (this.randomAccessFile != null) {
|
||||
this.randomAccessFile.close();
|
||||
this.randomAccessFile = null;
|
||||
}
|
||||
}
|
||||
finally {
|
||||
this.lock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
private int readByte(long position) throws IOException {
|
||||
this.lock.lock();
|
||||
try {
|
||||
synchronized (this.monitor) {
|
||||
openIfNecessary();
|
||||
this.randomAccessFile.seek(position);
|
||||
return this.randomAccessFile.read();
|
||||
}
|
||||
finally {
|
||||
this.lock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -76,7 +76,7 @@ public class SpringApplicationBuilder {
|
||||
|
||||
private final SpringApplication application;
|
||||
|
||||
private volatile ConfigurableApplicationContext context;
|
||||
private ConfigurableApplicationContext context;
|
||||
|
||||
private SpringApplicationBuilder parent;
|
||||
|
||||
@ -145,9 +145,11 @@ public class SpringApplicationBuilder {
|
||||
}
|
||||
configureAsChildIfNecessary(args);
|
||||
if (this.running.compareAndSet(false, true)) {
|
||||
synchronized (this.running) {
|
||||
// If not already running copy the sources over and then run.
|
||||
this.context = build().run(args);
|
||||
}
|
||||
}
|
||||
return this.context;
|
||||
}
|
||||
|
||||
|
@ -29,8 +29,6 @@ import java.util.EnumSet;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.TreeMap;
|
||||
import java.util.concurrent.locks.Lock;
|
||||
import java.util.concurrent.locks.ReentrantLock;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import org.springframework.boot.convert.ApplicationConversionService;
|
||||
@ -260,11 +258,6 @@ public class ConfigTreePropertySource extends EnumerablePropertySource<Path> imp
|
||||
|
||||
private final Path path;
|
||||
|
||||
/**
|
||||
* Guards access to {@link #resource}.
|
||||
*/
|
||||
private final Lock resourceLock = new ReentrantLock();
|
||||
|
||||
private final Resource resource;
|
||||
|
||||
private final Origin origin;
|
||||
@ -348,15 +341,11 @@ public class ConfigTreePropertySource extends EnumerablePropertySource<Path> imp
|
||||
}
|
||||
if (this.content == null) {
|
||||
assertStillExists();
|
||||
this.resourceLock.lock();
|
||||
try {
|
||||
synchronized (this.resource) {
|
||||
if (this.content == null) {
|
||||
this.content = FileCopyUtils.copyToByteArray(this.resource.getInputStream());
|
||||
}
|
||||
}
|
||||
finally {
|
||||
this.resourceLock.unlock();
|
||||
}
|
||||
}
|
||||
return this.content;
|
||||
}
|
||||
|
@ -38,15 +38,17 @@ public class SimpleFormatter extends Formatter {
|
||||
|
||||
private final String pid = getOrUseDefault(LoggingSystemProperty.PID.getEnvironmentVariableName(), "????");
|
||||
|
||||
private final Date date = new Date();
|
||||
|
||||
@Override
|
||||
public String format(LogRecord record) {
|
||||
Date date = new Date(record.getMillis());
|
||||
public synchronized String format(LogRecord record) {
|
||||
this.date.setTime(record.getMillis());
|
||||
String source = record.getLoggerName();
|
||||
String message = formatMessage(record);
|
||||
String throwable = getThrowable(record);
|
||||
String thread = getThreadName();
|
||||
return String.format(this.format, date, source, record.getLoggerName(), record.getLevel().getLocalizedName(),
|
||||
message, throwable, thread, this.pid);
|
||||
return String.format(this.format, this.date, source, record.getLoggerName(),
|
||||
record.getLevel().getLocalizedName(), message, throwable, thread, this.pid);
|
||||
}
|
||||
|
||||
private String getThrowable(LogRecord record) {
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2012-2023 the original author or authors.
|
||||
* Copyright 2012-2020 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.
|
||||
@ -16,8 +16,6 @@
|
||||
|
||||
package org.springframework.boot.security.reactive;
|
||||
|
||||
import java.util.concurrent.locks.Lock;
|
||||
import java.util.concurrent.locks.ReentrantLock;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
import reactor.core.publisher.Mono;
|
||||
@ -46,7 +44,7 @@ public abstract class ApplicationContextServerWebExchangeMatcher<C> implements S
|
||||
|
||||
private volatile Supplier<C> context;
|
||||
|
||||
private final Lock contextLock = new ReentrantLock();
|
||||
private final Object contextLock = new Object();
|
||||
|
||||
public ApplicationContextServerWebExchangeMatcher(Class<? extends C> contextClass) {
|
||||
Assert.notNull(contextClass, "Context class must not be null");
|
||||
@ -83,17 +81,13 @@ public abstract class ApplicationContextServerWebExchangeMatcher<C> implements S
|
||||
|
||||
protected Supplier<C> getContext(ServerWebExchange exchange) {
|
||||
if (this.context == null) {
|
||||
this.contextLock.lock();
|
||||
try {
|
||||
synchronized (this.contextLock) {
|
||||
if (this.context == null) {
|
||||
Supplier<C> createdContext = createContext(exchange);
|
||||
initialized(createdContext);
|
||||
this.context = createdContext;
|
||||
}
|
||||
}
|
||||
finally {
|
||||
this.contextLock.unlock();
|
||||
}
|
||||
}
|
||||
return this.context;
|
||||
}
|
||||
|
@ -16,8 +16,6 @@
|
||||
|
||||
package org.springframework.boot.security.servlet;
|
||||
|
||||
import java.util.concurrent.locks.Lock;
|
||||
import java.util.concurrent.locks.ReentrantLock;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
import jakarta.servlet.http.HttpServletRequest;
|
||||
@ -47,7 +45,7 @@ public abstract class ApplicationContextRequestMatcher<C> implements RequestMatc
|
||||
|
||||
private volatile boolean initialized;
|
||||
|
||||
private final Lock initializeLock = new ReentrantLock();
|
||||
private final Object initializeLock = new Object();
|
||||
|
||||
public ApplicationContextRequestMatcher(Class<? extends C> contextClass) {
|
||||
Assert.notNull(contextClass, "Context class must not be null");
|
||||
@ -63,16 +61,12 @@ public abstract class ApplicationContextRequestMatcher<C> implements RequestMatc
|
||||
}
|
||||
Supplier<C> context = () -> getContext(webApplicationContext);
|
||||
if (!this.initialized) {
|
||||
this.initializeLock.lock();
|
||||
try {
|
||||
synchronized (this.initializeLock) {
|
||||
if (!this.initialized) {
|
||||
initialized(context);
|
||||
this.initialized = true;
|
||||
}
|
||||
}
|
||||
finally {
|
||||
this.initializeLock.unlock();
|
||||
}
|
||||
}
|
||||
return matches(request, context);
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2012-2023 the original author or authors.
|
||||
* Copyright 2012-2022 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.
|
||||
@ -28,8 +28,6 @@ import java.nio.file.attribute.PosixFilePermissions;
|
||||
import java.security.MessageDigest;
|
||||
import java.util.EnumSet;
|
||||
import java.util.HexFormat;
|
||||
import java.util.concurrent.locks.Lock;
|
||||
import java.util.concurrent.locks.ReentrantLock;
|
||||
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.StringUtils;
|
||||
@ -53,11 +51,6 @@ public class ApplicationTemp {
|
||||
|
||||
private volatile Path path;
|
||||
|
||||
/**
|
||||
* Guards access to {@link #path}.
|
||||
*/
|
||||
private final Lock pathLock = new ReentrantLock();
|
||||
|
||||
/**
|
||||
* Create a new {@link ApplicationTemp} instance.
|
||||
*/
|
||||
@ -97,14 +90,10 @@ public class ApplicationTemp {
|
||||
|
||||
private Path getPath() {
|
||||
if (this.path == null) {
|
||||
this.pathLock.lock();
|
||||
try {
|
||||
synchronized (this) {
|
||||
String hash = HexFormat.of().withUpperCase().formatHex(generateHash(this.sourceClass));
|
||||
this.path = createDirectory(getTempDirectory().resolve(hash));
|
||||
}
|
||||
finally {
|
||||
this.pathLock.unlock();
|
||||
}
|
||||
}
|
||||
return this.path;
|
||||
}
|
||||
|
@ -20,8 +20,6 @@ import java.io.IOException;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
import java.util.concurrent.locks.Lock;
|
||||
import java.util.concurrent.locks.ReentrantLock;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
@ -59,7 +57,7 @@ public class JettyWebServer implements WebServer {
|
||||
|
||||
private static final Log logger = LogFactory.getLog(JettyWebServer.class);
|
||||
|
||||
private final Lock lock = new ReentrantLock();
|
||||
private final Object monitor = new Object();
|
||||
|
||||
private final Server server;
|
||||
|
||||
@ -115,7 +113,7 @@ public class JettyWebServer implements WebServer {
|
||||
}
|
||||
|
||||
private void initialize() {
|
||||
this.lock.lock();
|
||||
synchronized (this.monitor) {
|
||||
try {
|
||||
// Cache the connectors and then remove them to prevent requests being
|
||||
// handled before the application context is ready.
|
||||
@ -130,8 +128,6 @@ public class JettyWebServer implements WebServer {
|
||||
stopSilently();
|
||||
throw new WebServerException("Unable to start embedded Jetty web server", ex);
|
||||
}
|
||||
finally {
|
||||
this.lock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
@ -146,8 +142,7 @@ public class JettyWebServer implements WebServer {
|
||||
|
||||
@Override
|
||||
public void start() throws WebServerException {
|
||||
this.lock.lock();
|
||||
try {
|
||||
synchronized (this.monitor) {
|
||||
if (this.started) {
|
||||
return;
|
||||
}
|
||||
@ -184,9 +179,6 @@ public class JettyWebServer implements WebServer {
|
||||
throw new WebServerException("Unable to start embedded Jetty server", ex);
|
||||
}
|
||||
}
|
||||
finally {
|
||||
this.lock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
String getStartedLogMessage() {
|
||||
@ -249,8 +241,7 @@ public class JettyWebServer implements WebServer {
|
||||
|
||||
@Override
|
||||
public void stop() {
|
||||
this.lock.lock();
|
||||
try {
|
||||
synchronized (this.monitor) {
|
||||
this.started = false;
|
||||
if (this.gracefulShutdown != null) {
|
||||
this.gracefulShutdown.abort();
|
||||
@ -267,22 +258,17 @@ public class JettyWebServer implements WebServer {
|
||||
throw new WebServerException("Unable to stop embedded Jetty server", ex);
|
||||
}
|
||||
}
|
||||
finally {
|
||||
this.lock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void destroy() {
|
||||
this.lock.lock();
|
||||
synchronized (this.monitor) {
|
||||
try {
|
||||
this.server.stop();
|
||||
}
|
||||
catch (Exception ex) {
|
||||
throw new WebServerException("Unable to destroy embedded Jetty server", ex);
|
||||
}
|
||||
finally {
|
||||
this.lock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -20,8 +20,6 @@ import java.util.Arrays;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
import java.util.concurrent.locks.Lock;
|
||||
import java.util.concurrent.locks.ReentrantLock;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import javax.naming.NamingException;
|
||||
@ -62,7 +60,7 @@ public class TomcatWebServer implements WebServer {
|
||||
|
||||
private static final AtomicInteger containerCounter = new AtomicInteger(-1);
|
||||
|
||||
private final Lock lock = new ReentrantLock();
|
||||
private final Object monitor = new Object();
|
||||
|
||||
private final Map<Service, Connector[]> serviceConnectors = new HashMap<>();
|
||||
|
||||
@ -108,7 +106,7 @@ public class TomcatWebServer implements WebServer {
|
||||
|
||||
private void initialize() throws WebServerException {
|
||||
logger.info("Tomcat initialized with " + getPortsDescription(false));
|
||||
this.lock.lock();
|
||||
synchronized (this.monitor) {
|
||||
try {
|
||||
addInstanceIdToEngineName();
|
||||
|
||||
@ -143,8 +141,6 @@ public class TomcatWebServer implements WebServer {
|
||||
destroySilently();
|
||||
throw new WebServerException("Unable to start embedded Tomcat", ex);
|
||||
}
|
||||
finally {
|
||||
this.lock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
@ -209,8 +205,7 @@ public class TomcatWebServer implements WebServer {
|
||||
|
||||
@Override
|
||||
public void start() throws WebServerException {
|
||||
this.lock.lock();
|
||||
try {
|
||||
synchronized (this.monitor) {
|
||||
if (this.started) {
|
||||
return;
|
||||
}
|
||||
@ -238,9 +233,6 @@ public class TomcatWebServer implements WebServer {
|
||||
ContextBindings.unbindClassLoader(context, context.getNamingToken(), getClass().getClassLoader());
|
||||
}
|
||||
}
|
||||
finally {
|
||||
this.lock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
String getStartedLogMessage() {
|
||||
@ -332,8 +324,7 @@ public class TomcatWebServer implements WebServer {
|
||||
|
||||
@Override
|
||||
public void stop() throws WebServerException {
|
||||
this.lock.lock();
|
||||
try {
|
||||
synchronized (this.monitor) {
|
||||
boolean wasStarted = this.started;
|
||||
try {
|
||||
this.started = false;
|
||||
@ -351,9 +342,6 @@ public class TomcatWebServer implements WebServer {
|
||||
}
|
||||
}
|
||||
}
|
||||
finally {
|
||||
this.lock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -25,8 +25,6 @@ import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.atomic.AtomicReference;
|
||||
import java.util.concurrent.locks.Lock;
|
||||
import java.util.concurrent.locks.ReentrantLock;
|
||||
|
||||
import io.undertow.Undertow;
|
||||
import io.undertow.server.HttpHandler;
|
||||
@ -65,7 +63,7 @@ public class UndertowWebServer implements WebServer {
|
||||
|
||||
private final AtomicReference<GracefulShutdownCallback> gracefulShutdownCallback = new AtomicReference<>();
|
||||
|
||||
private final Lock lock = new ReentrantLock();
|
||||
private final Object monitor = new Object();
|
||||
|
||||
private final Undertow.Builder builder;
|
||||
|
||||
@ -106,8 +104,7 @@ public class UndertowWebServer implements WebServer {
|
||||
|
||||
@Override
|
||||
public void start() throws WebServerException {
|
||||
this.lock.lock();
|
||||
try {
|
||||
synchronized (this.monitor) {
|
||||
if (this.started) {
|
||||
return;
|
||||
}
|
||||
@ -139,9 +136,6 @@ public class UndertowWebServer implements WebServer {
|
||||
}
|
||||
}
|
||||
}
|
||||
finally {
|
||||
this.lock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
private void destroySilently() {
|
||||
@ -274,8 +268,7 @@ public class UndertowWebServer implements WebServer {
|
||||
|
||||
@Override
|
||||
public void stop() throws WebServerException {
|
||||
this.lock.lock();
|
||||
try {
|
||||
synchronized (this.monitor) {
|
||||
if (!this.started) {
|
||||
return;
|
||||
}
|
||||
@ -293,9 +286,6 @@ public class UndertowWebServer implements WebServer {
|
||||
throw new WebServerException("Unable to stop Undertow", ex);
|
||||
}
|
||||
}
|
||||
finally {
|
||||
this.lock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
|
Loading…
Reference in New Issue
Block a user