美好的一天! 我遇到了在java中同步线程的问题。我正在开发创建计时器的程序,并允许重置,删除和停止。只是为了学习如何使用线程。
问题是代码只给了一段时间同步......我无法理解我的错误。也许我的方式是错的,所以我想知道如何解决这个问题。
我有下一个代码:
public class StopWatch
{
//Create and start our timer
public synchronized void startClock( final int id )
{
//Creating new thread.
thisThread = new Thread()
{
@Override
public void run()
{
try
{
while( true )
{
System.out.printf( "Thread [%d] = %d\n", id, timerTime );
timerTime += DELAY; //Count 100 ms
Thread.sleep( DELAY );
}
}
catch( InterruptedException ex )
{
ex.printStackTrace();
}
}
};
thisThread.start();
}
…
//Starting value of timer
private long timerTime = 0;
//Number of ms to add and sleep
private static final int DELAY = 100;
private Thread thisThread;
}
我将此类称为:
StopWatch s = new StopWatch(1);
s.startClock();
StopWatch s2 = new StopWatch(2);
s2.startClock();
答案 0 :(得分:6)
我想你可能误解了“同步”。
这并不意味着线程在完全同步的时间内运行 - 而是一次只允许一个线程执行同步代码块。在你的情况下,“synchronized”没有区别,因为你是从同一个线程调用startClock方法....
通常,Java(实际上是大多数高级语言)都不可能保证两个线程在完全相同的时钟时间执行操作,即使您有多个内核,因为它们总是容易被操作系统延迟调度程序或JVM垃圾收集暂停等。
另外,Thread.sleep(...)作为计时机制是不可靠的,因为它睡眠的数量只是近似值。你受线程调度程序的支配。
建议的解决方案:
如果你想要一个与线程无关的计时机制,请使用System.currentTimeMillis()。
答案 1 :(得分:2)
你是什么意思"只能让你同步一段时间?"你在这里同步的唯一一件事是startClock方法,这意味着两个线程不会同时在该方法中(并且它看起来不像你正在做的那样)。例如,如果要同步对timerTime的访问,则需要在递增timerTime周围的thread run方法中放置一个synchronized块(或者你可以使用AtomicLong)。
答案 2 :(得分:0)
您可能应该重新阅读“synchronize”关键字的文档。我非常确定在这种情况下它所做的就是保持两个StartClock()调用同时执行,这不会发生,因为它们是从一个线程一个接一个地调用的。一旦计时器线程开始,如果这是你的目标,就没有什么能保持它们的同步。
答案 3 :(得分:0)
您的第一个问题是这是一个仅限时间的解决方案。这很糟糕,因为程序无法控制执行所需的时间。某些操作比其他操作花费更多时间,并且进程中的每个线程不会同时执行。一般来说,这不会同步任何东西,除非你能保证其他一切都是一样的。 。
了解http://download.oracle.com/javase/6/docs/api/java/util/concurrent/Semaphore.html,您也可以
的Thread.join();使主循环等待子线程的执行在继续执行之前完成。
答案 4 :(得分:0)
我认为你误解了同步意味着什么。同步是为了确保多个线程对某个代码块的访问权限受到限制,这样就不会在两个线程之间产生冲突。
我认为您可能更感兴趣的是CyclicBarrier或CountDownLatch。两者都可以用来“同步”(在这种情况下是重载使用)多个线程,这样他们就可以尝试同时开始做事。
但是,请注意,多个线程无法在完全同一时刻执行操作。你几乎可以尝试在同一时间鼓励他们这样做。其余部分受制于系统核心的OS调度。如果你有一个核心,它们将永远不会同时运行。