Java中的线程同步

3

你好!我遇到了一个关于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();

3
我想你可能没有理解在编程中使用线程时,“同步”一词的含义。它与时间无关,涉及其他方面。请注意不要改变原意。 - Brian Roach
@Brian Roach 是的,你说得对。我这里有很多东西要学习。 - ExiRe
5个回答

6
我认为你可能误解了“synchronized”的含义。
它并不意味着线程以完全同步的时间运行 - 而是只允许一个线程在执行同步代码块时进行执行。在你的情况下,“synchronized”没有任何区别,因为你正在从同一线程中调用startClock方法....
通常,在Java(以及大多数高级语言)中,即使你有多个核心,也无法保证两个线程在完全相同的时钟时间执行操作,因为它们总是容易受到操作系统调度程序或JVM垃圾收集暂停等的影响。
此外,Thread.sleep(...) 作为计时机制是不可靠的,因为它睡眠的时间只是近似值。你要看线程调度器的脸色。
建议解决方案:
如果想要一个与线程无关的计时机制,请使用System.currentTimeMillis()

这是否意味着如果我同时启动2个计时器(使用线程),然后在同一时间停止它们,我无法保证相同的值?我的理解正确吗? - ExiRe
正确。线程休眠不是一个准确的计时机制。如果您想要一个一致的计时器值,请使用System.currentTimeMillis()或类似方法。 - mikera
我从他的描述中了解到他所要求的内容,并且 synchronized 关键字并不能提供它。即使其他所有条件都相同,由于他使用了 synchronized 关键字,它们也永远不会同时运行,而且总是会出错。 - user328898

2
你说的“只能同步一段时间”是什么意思?在这里你所同步的仅仅是startClock方法,它只是确保两个线程不会同时进入该方法(而且看起来你也没有这样做)。如果你想同步对timerTime的访问,你需要在线程运行方法内部放置一个同步块,用于增加timerTime(或者你可以使用AtomicLong)。

0
你应该重新阅读“同步”关键字的文档。我相信在这种情况下,它只会防止两个StartClock()调用同时执行,但是由于它们是从一个线程依次调用的,所以这种情况不会发生。一旦计时器线程开始,如果这是你的目标,就没有什么可以保持它们同步了。

0
你的第一个问题是这只是一个基于时间的解决方案。这很糟糕,因为程序无法控制执行所需的时间。有些操作需要更长的时间,而进程中的每个线程并不同时执行。通常情况下,除非您可以保证其他所有内容都相同,否则这不会同步任何内容...。
阅读关于http://download.oracle.com/javase/6/docs/api/java/util/concurrent/Semaphore.html的内容,您也可以使用Thread.join();使主循环等待子线程执行完成后再继续执行。

0

我认为你误解了synchronized的含义。Synchronized是为了确保多个线程对某个代码块的访问受到限制,以避免两个线程之间发生冲突。

我认为你更感兴趣的可能是CyclicBarrier或CountDownLatch。两者都可以用于“同步”(在这种情况下是过载使用)多个线程,以便它们尝试同时开始执行任务。

但是,请注意,不可能让多个线程在完全相同的时间做事情。你只能尝试鼓励它们在大约相同的时间内执行任务。其余的取决于系统中核心的操作系统调度。如果只有一个核心,它们永远不会同时运行。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接