线程加入似乎是死锁

时间:2012-08-30 12:58:08

标签: java android multithreading

有人可以对报告的错误有所了解:

"main" prio=5 tid=1 WAIT
  | group="main" sCount=1 dsCount=0 obj=0x40b97568 self=0x40b5ba68
  | sysTid=29071 nice=0 sched=0/0 cgrp=apps handle=1074202160
  | schedstat=( 2218977000 625819000 2260 ) utm=177 stm=44 core=0
  at java.lang.Object.wait(Native Method)
  - waiting on <0x412f4160> (a java.lang.VMThread) held by tid=12 (Thread-699)
  at java.lang.Object.wait(Object.java:364)
  at java.lang.Thread.join(Thread.java:761)
  at com.pyesmeadow.pendulumclock.PendulumAppView.pause(PendulumAppView.java:419)

它似乎表明它正在等待ID为12的线程。查看堆栈跟踪,我对线程#12有以下内容:

"Thread-699" prio=5 tid=12 NATIVE
  | group="main" sCount=1 dsCount=0 obj=0x41715d38 self=0x678ba008
  | sysTid=29098 nice=0 sched=0/0 cgrp=apps handle=1642643840
  | schedstat=( 12528326000 501640000 3154 ) utm=1206 stm=46 core=0
  #00 pc 0000dc70 /system/lib/libc.so (__futex_syscall3+8)
  #01 pc 0001212c /system/lib/libc.so
  #02 pc 0001a9cf /system/lib/libgui.so
  #03 pc 00021351 /system/lib/libgui.so     (android::SurfaceTextureClient::disconnect(int)+32)
  #04 pc 000213c7 /system/lib/libgui.so     (android::SurfaceTextureClient::~SurfaceTextureClient()+22)
  #05 pc 00021445 /system/lib/libgui.so     (android::SurfaceTextureClient::~SurfaceTextureClient()+4)
  #06 pc 0000ee89 /system/lib/libutils.so (android::RefBase::decStrong(void const*) const+40)
  #07 pc 000497db /system/lib/libandroid_runtime.so (android::sp<android::InputChannel>::~sp()+10)
  #08 pc 000567e1 /system/lib/libandroid_runtime.so
  #09 pc 0001de30 /system/lib/libdvm.so (dvmPlatformInvoke+112)
  #10 pc 0004d083 /system/lib/libdvm.so (dvmCallJNIMethod(unsigned int const*, JValue*, Method const*, Thread*)+394)
  #11 pc 00027260 /system/lib/libdvm.so
  #12 pc 0002bb68 /system/lib/libdvm.so (dvmInterpret(Thread*, Method const*, JValue*)+180)
  #13 pc 0005f7f1 /system/lib/libdvm.so (dvmCallMethodV(Thread*, Method const*, Object*, bool, JValue*, std::__va_list)+272)
  #14 pc 0005f81b /system/lib/libdvm.so (dvmCallMethod(Thread*, Method const*, Object*, JValue*, ...)+20)
  #15 pc 000543d3 /system/lib/libdvm.so
  #16 pc 00012dd0 /system/lib/libc.so (__thread_entry+48)
  #17 pc 00012528 /system/lib/libc.so (pthread_create+172)
  at android.view.Surface.isValid(Native Method)
  at com.pyesmeadow.pendulumclock.PendulumAppView$WorkerThread.run(PendulumAppView.java:169)

基本上,该线程负责更新UI。它所指的代码行是对isValid()的调用:

if( _surfaceHolder.getSurface().isValid() )
{
    // ...
}

回到第一个堆栈转储(上图),似乎问题出现在_workerThread.join()的调用中(_workerThread是ID为#12的线程):

public void pause()
{   
    _workerThread.setRunning( false );

    // Wait for the background thread to terminate.

    while( true )
    {
        try
        {
            _workerThread.join();
            break;
        }
        catch( InterruptedException ex )
        {
        }
    }
}

似乎通过在工作线程上调用join()发生了死锁,但我不知道为什么。

任何帮助都将不胜感激。

韦恩。

** * *** 更新 ** * ** * ****

以下是工作线程中run()方法的代码:

(请注意,在我的代码的生产版本中_running \是非易失性布尔值)

    public void setRunning( boolean flag )
    {
        _running = flag;
    }

    @Override
    public void run()
    {   
        int previousIndex = 0;

        _timeSwingStarted = new Date();

        while( _running )
        {
            if( _swingPath == null || _swingPath.isEmpty() )
                continue;

            if( Thread.interrupted() )
                break;

            if( _mode == PendulumMode.Swinging )
            {
                Date current = new Date();
                long elapsed = current.getTime() - _timeSwingStarted.getTime();
                int index = (int) Math.floor( ((double) Math.min(elapsed, 2000.0f) / 2000.0f) * (_swingPath.size() - 1) );

                index = Math.max( Math.min( index, _swingPath.size() - 1), 0 );

                if( index == previousIndex )
                    continue;

                // Calculate the position of the pendulum and render it on the display

                _currentPosition = _swingPath.get( index );

                // only render the UI if there is a valid surface to render on

                if( _surfaceHolder.getSurface().isValid() )
                    _theme.render( _currentPosition, _scrollOffsetY, _showFPS );

                // Check whether the direction of the pendulum has changed

                previousIndex = index;

                if( index >= _swingPath.size() - 1 )
                    _timeSwingStarted = new Date();
            }


            //
            // Check whether we should close the app automatically if a
            // specified battery level has been reached.
            //

            if( _closeWhenBatteryLow && isBatteryLevelBelowThreshold() )
            {
                //
                // Schedule a shutdown time and notify the user in case they wish
                // to change their minds by adjusting the app settings.
                //

                if( _shutDownTime == null )
                {
                    _shuttingDownReason = ShutdownReason.BatteryLow;
                    _shutDownTime = Calendar.getInstance();
                    _shutDownTime.add( Calendar.MINUTE, 2 );

                    ((Activity) _context).runOnUiThread( new Runnable() {
                        public void run() {
                            showWarning( getResources().getString( R.string.batteryLowClosingMessage ) );
                        }
                    });
                }
            }

            //
            // Determine whether it's time to shutdown the app, if so the perform
            // some extra checks to ensure that the user hasn't changed their minds
            // since the initial message was displayed.
            //

            if( _shutDownTime != null )
            {
                Calendar now = Calendar.getInstance();

                if( now.after( _shutDownTime ) )
                {
                    if( _shuttingDownReason == ShutdownReason.BatteryLow )
                    {
                        if( _closeWhenBatteryLow && isBatteryLevelBelowThreshold() )
                        {
                            ((Activity) _context).finish();
                        }
                        else
                        {
                            _shuttingDownReason = ShutdownReason.None;
                            _shutDownTime = null;
                        }
                    }
                }
            }

            try
            {
                Thread.sleep( _sleepDuration );
            }
            catch( InterruptedException e )
            {
                /* at least we tried */
            }
        }
    }

2 个答案:

答案 0 :(得分:1)

这一行似乎表明存在问题:

_workerThread.setRunning( false );

您是否在某处查询布尔标志以查看是否需要停止?在这种情况下应该声明volatile

答案 1 :(得分:0)

尝试:

    while( true ){
        _workerThread.interrupt();
        try
        {
            _workerThread.join();
            break;
        }
        catch( InterruptedException ex )
        {
        }
     }

使用我的线程它可以正常工作..

修改

都铎在我的帖子评论中有你的解决方案。