更有效的方式来暂停循环想要的
是否有可能重写这个代码,以更好地使用处理器? 我有一个类,它在一个单独的线程中执行固定的周期的一些任务。 有时这个过程可以暂停和恢复。 目前我正在使用一个标志暂停,它工作正常,但循环这种方式仍然加载处理器时进程暂停。 有没有可能解决这个问题?
private boolean mIsCanceled = false; private boolean mIsPaused = true; // TODO more efficient for processor way of pausing is required private final Thread mTimerThread = new Thread(new Runnable() { @Override public void run() { while(!mIsCanceled){ try { Thread.sleep(UPDATE_PERIOD); } catch (InterruptedException e) { e.printStackTrace(); } if (!mIsPaused){ doStep(); } } } }); public MyClass(){ mTimerThread.start(); } private void pause(){ mIsPaused = true; } private void resume(){ mIsPaused = false; } private void doStep(){ // Some code }
请只提供我的代码的替代实现。
PS环境是Android OS 2.2+
可用的工具是:
wait
/ notify
– 我们都试图摆脱这个古老的系统。
Semaphore
– 一旦你的线程抓住它,你将它保持到释放,所以再次抓住它不会阻塞。 这意味着你不能在你自己的线程内暂停。
CyclicBarrier
– 每次使用时都必须重新创build。
ReadWriteLock
– 我的最爱。 你可以有任意多的线程暂停你,只有当他们都打电话给resume
。 如果你愿意,你甚至可以暂停自己。
import java.util.concurrent.locks.ReadWriteLock; import java.util.concurrent.locks.ReentrantReadWriteLock; /** * PauseableThread is a Thread with pause/resume and cancel methods. * * The meat of the process must implement `step`. * * You can either extend this and implement `step` or use the factory. * * Note that I cannot extend Thread because my resume will clash with Thread's deprecated one. * * Usage: Either write a `Stepper` and run it in a `PausableThread` or extend `PausableThread` and call `blockIfPaused()` at appropriate points. */ public abstract class PauseableThread implements Runnable { // The lock. // We'll hold a read lock on it to pause the thread. // The thread will momentarily grab a write lock on it to pause. // This way you can have multiple pausers using normal locks. private final ReadWriteLock pause = new ReentrantReadWriteLock(); // Flag to cancel the wholeprocess. private volatile boolean cancelled = false; // The exception that caused it to finish. private Exception thrown = null; @Override // The core run mechanism. public void run() { try { while (!cancelled) { // Block here if we're paused. blockIfPaused(); // Do my work. step(); } } catch (Exception ex) { // Just fall out when exception is thrown. thrown = ex; } } // Block if pause has been called without a matching resume. private void blockIfPaused() throws InterruptedException { try { // Grab a write lock. Will block if a read lock has been taken. pause.writeLock().lockInterruptibly(); } finally { // Release the lock immediately to avoid blocking when pause is called. pause.writeLock().unlock(); } } // Pause the work. NB: MUST be balanced by a resume. public void pause() { // We can wait for a lock here. pause.readLock().lock(); } // Resume the work. NB: MUST be balanced by a pause. public void resume() { // Release the lock. pause.readLock().unlock(); } // Stop. public void cancel() { // Stop everything. cancelled = true; } // start - like a thread. public void start() { // Wrap it in a thread. new Thread(this).start(); } // Get the exceptuion that was thrown to stop the thread or null if the thread was cancelled. public Exception getThrown() { return thrown; } // Create this method to do stuff. // Calls to this method will stop when pause is called. // Any thrown exception stops the whole process. public abstract void step() throws Exception; // Factory to wrap a Stepper in a PauseableThread public static PauseableThread make(Stepper stepper) { StepperThread pauseableStepper = new StepperThread(stepper); // That's the thread they can pause/resume. return pauseableStepper; } // One of these must be used. public interface Stepper { // A Stepper has a step method. // Any exception thrown causes the enclosing thread to stop. public void step() throws Exception; } // Holder for a Stepper. private static class StepperThread extends PauseableThread { private final Stepper stepper; StepperThread(Stepper stepper) { this.stepper = stepper; } @Override public void step() throws Exception { stepper.step(); } } // My test counter. static int n = 0; // Test/demo. public static void main(String[] args) throws InterruptedException { try { // Simple stepper that just increments n. Stepper s = new Stepper() { @Override public void step() throws Exception { n += 1; Thread.sleep(10); } }; PauseableThread t = PauseableThread.make(s); // Start it up. t.start(); Thread.sleep(1000); t.pause(); System.out.println("Paused: " + n); Thread.sleep(1000); System.out.println("Resuminng: " + n); t.resume(); Thread.sleep(1000); t.cancel(); } catch (Exception e) { } } }
编辑:代码修改为更一般的使用。
你最好的select是使用wait()/ notify()或简单地切换到ScheduledExecutorService
适当的wait()/ notify()用法可能会非常棘手。 我强烈build议“实践中的Java并发”来了解关于线程的更多信息。
我相信这里最好的方法是使用Thread.wait
等待线程而不是睡眠,并在正在等待的线程中使用Thread.notify
。 更多信息在这里: http : //www.javamex.com/tutorials/synchronization_wait_notify.shtml
您可以通过使用监视器而不是睡觉线程来提高效率。 您只需在代码中使用关键字同步即可创build块。 最后一个对象是监视器。 在监视器的API中查看更多。