DZone
Web Dev Zone
Thanks for visiting DZone today,
Edit Profile
  • Manage Email Subscriptions
  • How to Post to DZone
  • Article Submission Guidelines
Sign Out View Profile
  • Post an Article
  • Manage My Drafts
Over 2 million developers have joined DZone.
Log In / Join
  • Refcardz
  • Trend Reports
  • Webinars
  • Zones
  • |
    • Agile
    • AI
    • Big Data
    • Cloud
    • Database
    • DevOps
    • Integration
    • IoT
    • Java
    • Microservices
    • Open Source
    • Performance
    • Security
    • Web Dev
DZone > Web Dev Zone > How to Test if Your Tomcat Web Application Is Thread Safe

How to Test if Your Tomcat Web Application Is Thread Safe

In this quick tutorial, a Java dev shows us the ropes (or should I say threads?) of thread safety in Tomcat-based web applications.

Thomas Krieger user avatar by
Thomas Krieger
·
Oct. 26, 17 · Web Dev Zone · Tutorial
Like (8)
Save
Tweet
6.72K Views

Join the DZone community and get the full member experience.

Join For Free

in the following, i want to show you how to test if your tomcat web application is thread-safe. as an example application, i use jenkins deployed on an apache tomcat 9.0.

to detect concurrency bugs during our tests we use vmlens . vmlens traces the test execution and analyzes the trace afterward. it detects deadlocks and race conditions during the test run.

testing

to enable vmlens we add it as java agent to the catalina_opts in catalina.sh on linux or catalina.bat on windows:

catalina_opts="-javaagent:<path to agent> -xmx8g"

we also set a high enough heap size. after running jenkins and executing some build jobs we see the following report in vmlens:

image title

analyzing

let us look at one of the races found, the race at accessing the field hudson.udpbroadcastthread.shutdown.

image title

the thread "jenkins udp 33848 monitoring thread" reads the field in the race and the thread "localhost-startstop-2" writes it. let us look at the class and the reading method run() and the writing method shutdown() .

public class udpbroadcastthread extends thread {
    private boolean shutdown;
public void run() {
        try {
            mcs.joingroup(multicast);
            ready.signal();
            while(true) {
                byte[] buf = new byte[2048];
                datagrampacket p = new datagrampacket(buf,buf.length);
                mcs.receive(p);
                socketaddress sender = p.getsocketaddress();
                // prepare a response
                tcpslaveagentlistener tal = jenkins.gettcpslaveagentlistener();
                stringbuilder rsp = new stringbuilder("<hudson>");
                tag(rsp,"version", jenkins.version);
                tag(rsp,"url", jenkins.getrooturl());
                tag(rsp,"server-id", jenkins.getlegacyinstanceid());
                tag(rsp,"slave-port",tal==null?null:tal.getport());
                for (udpbroadcastfragment f : udpbroadcastfragment.all())
                    f.buildfragment(rsp,sender);
                rsp.append("</hudson>");
                byte[] response = rsp.tostring().getbytes("utf-8");
                mcs.send(new datagrampacket(response,response.length,sender));
            }
        } catch (closedbyinterruptexception e) {
            // shut down
        } catch (socketexception e) {
            if (shutdown) { // forcibly closed
                return;
            }            // if we failed to listen to udp, just silently abandon it, as a stack trace
            // makes people unnecessarily concerned, for a feature that currently does no good.
            logger.log(level.info, "cannot listen to udp port {0}, skipping: {1}", new object[] {port, e});
            logger.log(level.fine, null, e);
        } catch (ioexception e) {
            if (shutdown)   return; // forcibly closed
            logger.log(level.warning, "udp handling problem",e);
            udphandlingproblem = true;
        }
    }
      public void shutdown() {
        shutdown = true;
        mcs.close();
        interrupt();
    }
}

the field shutdown is a nonvolatile field. it is read in line 28 and 35 in the method run and written in line 41 in the method shutdown

since the field hudson.udpbroadcastthread.shutdown is not volatile, it is not guaranteed that the "jenkins udp 33848 monitoring thread" sees the values set by the "localhost-startstop-2" thread.

the "jenkins udp 33848 monitoring thread" might, for example, run on the first core while "localhost-startstop-2" runs on the second core of a multi-core cpu. the write to a normal field does not invalidate the cache of the cores. therefore the "jenkins udp 33848 monitoring thread" still sees the cached old value.

Apache Tomcat Web application Testing

Published at DZone with permission of Thomas Krieger, DZone MVB. See the original article here.

Opinions expressed by DZone contributors are their own.

Popular on DZone

  • How to Configure Git in Eclipse IDE
  • OpenTelemetry in Action: Identifying Database Dependencies
  • Enough Already With ‘Event Streaming’
  • The Engineer’s Guide to Creating a Technical Debt Proposal

Comments

Web Dev Partner Resources

X

ABOUT US

  • About DZone
  • Send feedback
  • Careers
  • Sitemap

ADVERTISE

  • Advertise with DZone

CONTRIBUTE ON DZONE

  • Article Submission Guidelines
  • MVB Program
  • Become a Contributor
  • Visit the Writers' Zone

LEGAL

  • Terms of Service
  • Privacy Policy

CONTACT US

  • 600 Park Offices Drive
  • Suite 300
  • Durham, NC 27709
  • support@dzone.com
  • +1 (919) 678-0300

Let's be friends:

DZone.com is powered by 

AnswerHub logo