Below is my app's start/stop procedure, start/stop code is handled by a single-threaded ThreadPoolExecutor, so I'm guaranteed there's only one thread can be active at the same time.
I'm asking about isRunning variable. Is making the variable volatile enough?
The variable will be accessed (read/modify) from different threads (but only one at the same time!)
EDIT:
Added variable reading (beginning of startProcedure() and stopProcedure()). I forgot about that part, my apologies.
EDIT2:
I think it may be hard to notice, but startProcedure() and stopProcedure() are functions used to create startQuery and stopQuery - Runnables used by threads.
public final class Work {
    private static final ThreadPoolExecutor processor = new ThreadPoolExecutor(1, 1,
            0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<>(1),
            new ThreadPoolExecutor.DiscardPolicy());
    private static final Runnable startQuery = Work::startProcedure,
            stopQuery = Work::stopProcedure;
    private static boolean isRunning = false;
    private Work() {}
    private static void startProcedure() {
        if (isRunning) return;
        isRunning = true;
        //<some code>
    }
    private static void stopProcedure() {
        if (!isRunning) return;
        //<some code>
        isRunning = false;
    }
    //------Public API
    public static void start() {
        processor.execute(startQuery);
    }
    public static void stop() {
        processor.execute(stopQuery);
    }
}