如何启动线程?

时间:2014-04-17 16:14:49

标签: java android multithreading thread-safety

我有一个实例线程类。

public class LogThread extends Thread{

    private static LogThread instance = null;
    private volatile boolean isRunning = false;
    private final static Object instanceLock = new Object();

    public static synchronized LogThread getInstance(){
        synchronized(instanceLock){
            if(instance == null)
                instance = new LogThread();
        }
        return instance;
    }

    @Override
    public run(){
        //Doing some run stuff
        //Once run is finished

        synchronized(instanceLock){
            isRunning = false;
            instance = null;
        }
    }

    @Override
    public synchronized void start() {
        synchronized (instanceLock){
            if(!isRunning){
                isRunning = true;
                super.start();
            }
        }
    }
}

每次我获取实例时,我都会从另一个线程开始调用,每隔一段时间我就会在com中发现IllegalThreadStateException ... .. LogThread.start,第x行已经启动了线程。

如果我在启动线程之前设置isRunning并基于instanceLock同步它,那么线程如何已经启动。

EDIT :: 我已将我的getInstance()编辑到下面:

 public static synchronized LogThread getInstance(){
     synchronized(instanceLock){
         if(instance == null){
             instance = new LogThread();
             instance.start();
         }
     }
 }

它应该停止任何尝试启动已经启动的线程。

2 个答案:

答案 0 :(得分:2)

序列将是:

  • 主题A调用getInstance。线程A获取锁定一段时间,时间检查instance是否为空,此时它不是。
  • 线程LogThread完成它的执行,isRunning设置为false。 instance设置为false,但仍由Thread A
  • 保留
  • 线程A在实例上调用startisRunning为false,因此调用start,因此崩溃。

快速解决方法是不将isRunning设置为false,因为从来没有任何充分理由让该实例可以再次启动。然后应将其重命名为isStarted以确保与其一致。

正确的解决方案是使用newSingleThreadExecutor,如@Mani

所示

答案 1 :(得分:0)

It is never legal to start a thread more than once.
     * In particular, a thread may not be restarted once it has completed
     * execution.

来自Thread.start

您不应该启动已经启动的线程。即使线程完成它工作(运行完成)。

它只是检查threadStatus并抛出异常

  if (threadStatus != 0)
            throw new IllegalThreadStateException();

如果我清楚地理解,您希望确保只有一个线程用于此任务,并且您希望重用相同的线程。  恕我直言,你有两个选择,

选项1:每次创建新线程。确保前一个线程完成其工作。由于每次创建新线程都很昂贵,因此价格昂贵

选项2:Executors.newSingleThreadExecutor()使用此功能。这将确保只创建一个线程。

通常,避免扩展线程,使用Runnable

如果您只想使用一个主题。并且有很多乔布斯。你可以使用以下内容。

class LogJob implements Runnable{
    @Override
    public void run() {
        // Do your Job
    }
}

  ExecutorService singleThread = Executors.newSingleThreadExecutor();
LogJob job = new LogJob();
for (int i=0;i<100;i++){
    singleThread.submit(job);
}
singleThread.shutdown();

//对于Demo,我把它放在循环中。您只需拨打singleThread.submit(job);即可。最多只有一个Job会在任何给定时间运行。你所有的工作都会强制执行。

您不需要任何同步块/方法