
Leading the Way: Payara Platform Community 7 Beta Now Fully Jakarta EE 11 Certified
We’re excited to announce that Payara Platform Community 7 Beta application server is now fully certified as Jakarta EE 11 […]
The previous part of this blog showed how to take a thread dump of Payara Server. This part will go through reading these thread dumps, particularly in regard to identifying deadlocks.
Below is a breakdown of a thread dump.
prio
and os_prio
show these as reported by Java and the OS respectively.tid
, and is the one that would be returned by thread.getId()
. The OS thread id is called nid
, and is useful for referring to a thread when seeing if a thread is taking up too much memory.
A deadlock is when two or more threads have a lock over some resources and are both waiting for each other to give up their lock, which causes them to hang. Deadlocks aren’t always easy to spot, but they can be extremely problematic when they occur. They are often only stopped by restarting the server and removing the problem.
Below, I have made a simple servlet to demonstrate the problem by creating a deadlock when it receives too many requests at once:
@WebServlet("/deadlock")
public class DeadlockServlet extends HttpServlet {
@Inject
private Model model;
@Inject
private View view;
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException{
resp.getWriter().println("Request completed.n");
for(String key: req.getParameterMap().keySet()){
model.putData(key, req.getParameterMap().get(key)[0]);
}
view.update(resp.getWriter());
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException{
doGet(req, resp);
}
}
Although, in reality, for something like this you would normally want to use something like CDI Events, this method suits the purpose of creating a deadlock. There is nothing immediately wrong with this servlet. On a GET
request it will add each key-value pair parameter to an injected model, and it will call the view in order to print it to the response.
@ApplicationScoped
public class Model implements Serializable{
private Map<String, String> data;
@Inject
private View view;
@PostConstruct
private void init() {
data = new HashMap<>();
}
public synchronized void putData(String key, String value){
data.put(key, value);
view.update(new PrintWriter(System.out));
}
public synchronized String getData(){
String content = "";
for(String key: this.data.keySet()){
content += key+ ": " + this.data.get(key) + "n";
}
return content;
}
}
The Model bean is @ApplicationScoped
, meaning that there is only one per application instance – in other words, every user will use the same model, and will be able to see and add to the same list. The model is just a map of key-value pairs. it can put data into that map, and return a string representation of it. Both of these operations are synchronized
, meaning that multiple threads can’t manipulate the model at the same time.
@ApplicationScoped
public class View {
@Inject
private Model model;
public synchronized void update(PrintWriter out) {
out.println(model.getData());
}
}
The View bean is also @ApplicationScoped
. It has a synchronized
method which allows the view to print the model to a given PrintWriter
.
Each user of a servlet is given their own thread. Knowing this, there doesn’t appear to be any code that would cause a threading problem. If however, one thread accesses the view’s update()
method whilst another thread accesses the model’s putData()
method, it will cause a deadlock. This is because the view object is waiting for the model’s lock, and the model object is waiting for the view’s lock, but neither will give up their lock. This will cause the two threads to hang, and will slow down your server. If you’re using VisualVM and you call this servlet enough times in a short space of time, you will see an error like this:
Even if you’re not using VisualVM, then take a thread dump and you’ll see the following problem.
As you can see the two threads here are waiting on each other. The first trace stack is pointing towards Model.putData()
, and the second is pointing towards View.update()
. This is the cause of the problem, and will give you a good starting point for your investigation on fixing the problem.
We’re excited to announce that Payara Platform Community 7 Beta application server is now fully certified as Jakarta EE 11 […]
Enterprise Java applications power global commerce, healthcare, government and countless other industries. These systems must be scalable, secure and […]
May 2025 marks a monumental milestone in software development: Java turns 30. The impact of this language on the […]