BAEL-4615: Create and Detect Memory Leak in Java (#14060)
This commit is contained in:
parent
2091146702
commit
7317f0816d
|
@ -5,3 +5,4 @@ This module contains articles about performance of Java applications
|
|||
### Relevant Articles:
|
||||
- [Possible Root Causes for High CPU Usage in Java](https://www.baeldung.com/java-high-cpu-usage-causes)
|
||||
- [External Debugging With JMXTerm](https://www.baeldung.com/java-jmxterm-external-debugging)
|
||||
- [Create and Detect Memory Leaks in Java](https://www.baeldung.com/java-create-detect-memory-leaks)
|
||||
|
|
|
@ -13,4 +13,11 @@
|
|||
<version>0.0.1-SNAPSHOT</version>
|
||||
</parent>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>net.datafaker</groupId>
|
||||
<artifactId>datafaker</artifactId>
|
||||
<version>1.6.0</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</project>
|
|
@ -0,0 +1,35 @@
|
|||
package com.baeldung.lapsedlistener;
|
||||
|
||||
import static com.baeldung.lapsedlistener.UserGenerator.generateUser;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
public class LapsedListenerRunner {
|
||||
|
||||
private static final Logger logger = LoggerFactory.getLogger(LapsedListenerRunner.class);
|
||||
private static final MovieQuoteService movieQuoteService = new MovieQuoteService();
|
||||
|
||||
static {
|
||||
movieQuoteService.start();
|
||||
}
|
||||
|
||||
public static void main(String[] args) {
|
||||
while (true) {
|
||||
User user = generateUser();
|
||||
logger.debug("{} logged in", user.getName());
|
||||
user.subscribe(movieQuoteService);
|
||||
userUsingService();
|
||||
logger.debug("{} logged out", user.getName());
|
||||
}
|
||||
}
|
||||
|
||||
private static void userUsingService() {
|
||||
try {
|
||||
Thread.sleep(10);
|
||||
} catch (InterruptedException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,47 @@
|
|||
package com.baeldung.lapsedlistener;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.Executors;
|
||||
import java.util.concurrent.ScheduledExecutorService;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import net.datafaker.Faker;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
public class MovieQuoteService implements Subject {
|
||||
|
||||
private static final Logger logger = LoggerFactory.getLogger(MovieQuoteService.class);
|
||||
private final ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(1);
|
||||
private final List<Observer> observers = new ArrayList<>();
|
||||
private final Faker faker = new Faker();
|
||||
|
||||
@Override
|
||||
public void attach(Observer observer) {
|
||||
logger.debug("Current number of subscribed users: {}", observers.size());
|
||||
observers.add(observer);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void detach(Observer observer) {
|
||||
observers.remove(observer);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void notifyObservers() {
|
||||
String quote = faker.movie().quote();
|
||||
logger.debug("New quote: {}", quote);
|
||||
for (Observer observer : observers) {
|
||||
logger.debug("Notifying user: {}", observer);
|
||||
observer.update(quote);
|
||||
}
|
||||
}
|
||||
|
||||
public void start() {
|
||||
scheduler.scheduleAtFixedRate(this::notifyObservers, 0, 1, TimeUnit.SECONDS);
|
||||
}
|
||||
|
||||
public int numberOfSubscribers() {
|
||||
return observers.size();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,9 @@
|
|||
package com.baeldung.lapsedlistener;
|
||||
|
||||
public interface Observer {
|
||||
void update(String latestNews);
|
||||
|
||||
void subscribe(Subject subject);
|
||||
|
||||
void unsubscribe(Subject subject);
|
||||
}
|
|
@ -0,0 +1,9 @@
|
|||
package com.baeldung.lapsedlistener;
|
||||
|
||||
public interface Subject {
|
||||
void attach(Observer observer);
|
||||
|
||||
void detach(Observer observer);
|
||||
|
||||
void notifyObservers();
|
||||
}
|
|
@ -0,0 +1,70 @@
|
|||
package com.baeldung.lapsedlistener;
|
||||
|
||||
public class User implements Observer {
|
||||
|
||||
private final String name;
|
||||
private final String email;
|
||||
private final String phone;
|
||||
private final String street;
|
||||
private final String city;
|
||||
private final String state;
|
||||
private final String zipCode;
|
||||
|
||||
public User(String name, String email, String phone, String street, String city, String state, String zipCode) {
|
||||
this.name = name;
|
||||
this.email = email;
|
||||
this.phone = phone;
|
||||
this.street = street;
|
||||
this.city = city;
|
||||
this.state = state;
|
||||
this.zipCode = zipCode;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public String getEmail() {
|
||||
return email;
|
||||
}
|
||||
|
||||
public String getPhone() {
|
||||
return phone;
|
||||
}
|
||||
|
||||
public String getStreet() {
|
||||
return street;
|
||||
}
|
||||
|
||||
public String getCity() {
|
||||
return city;
|
||||
}
|
||||
|
||||
public String getState() {
|
||||
return state;
|
||||
}
|
||||
|
||||
public String getZipCode() {
|
||||
return zipCode;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void update(final String quote) {
|
||||
// user got updated with a new quote
|
||||
}
|
||||
|
||||
@Override
|
||||
public void subscribe(final Subject subject) {
|
||||
subject.attach(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void unsubscribe(final Subject subject) {
|
||||
subject.detach(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "User [name=" + name + "]";
|
||||
}
|
||||
}
|
|
@ -0,0 +1,23 @@
|
|||
package com.baeldung.lapsedlistener;
|
||||
|
||||
import net.datafaker.Faker;
|
||||
|
||||
public class UserGenerator {
|
||||
|
||||
private UserGenerator() {
|
||||
}
|
||||
|
||||
private static final Faker faker = new Faker();
|
||||
|
||||
public static User generateUser() {
|
||||
String name = faker.name().fullName();
|
||||
String email = faker.internet().emailAddress();
|
||||
String phone = faker.phoneNumber().cellPhone();
|
||||
String street = faker.address().streetAddress();
|
||||
String city = faker.address().city();
|
||||
String state = faker.address().state();
|
||||
String zipCode = faker.address().zipCode();
|
||||
return new User(name, email, phone, street, city, state, zipCode);
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,24 @@
|
|||
package com.baeldung.lapsedlistener;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
class MovieQuoteServiceTest {
|
||||
|
||||
@Test
|
||||
void whenSubscribeToService_thenServiceHasOneSubscriber() {
|
||||
MovieQuoteService service = new MovieQuoteService();
|
||||
service.attach(UserGenerator.generateUser());
|
||||
assertEquals(1, service.numberOfSubscribers());
|
||||
}
|
||||
|
||||
@Test
|
||||
void whenUnsubscribeFromService_thenServiceHasNoSubscribers() {
|
||||
MovieQuoteService service = new MovieQuoteService();
|
||||
User user = UserGenerator.generateUser();
|
||||
service.attach(user);
|
||||
service.detach(user);
|
||||
assertEquals(0, service.numberOfSubscribers());
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue