Java 线程和同步方法未按要求执行

Posted

技术标签:

【中文标题】Java 线程和同步方法未按要求执行【英文标题】:Java thread and synchronised methods not performing as required 【发布时间】:2021-04-06 23:28:09 【问题描述】: 我连续 2 天以来一直在尝试,并且已经就相关问题提出了许多 SO 问题和答案。

上下文:

    Runnable 类从另一个服务类获得多个调用。 Runnable 类必须在重新启动之前完成已经运行和同步的方法

从服务调用 Runnable 线程:

final Singular_Processor singularProcessor = new Singular_Processor(this);
singularProcessor.start();
synchronized(singularProcessor.context)

     while(singularProcessor.needWait)
     
          wait();
     

实际可运行线程类:

class Singular_Processor extends Thread

    private static final String TAG = "Singular_Processor";
    final Context context;
    boolean needWait = false;

    Singular_Processor(Context context)
    
        this.context = context;
    

    @Override
    public void run()
    
        try
        
            doNotDisturbMe();
        
        catch (Exception e)
        
            e.printStackTrace();
        
    

    private void doNotDisturbMe()
    
        synchronized (context)
        
            try
            
                needWait = true;
                Log.d(TAG, "RUNNING THE THREAD ID : " + Thread.currentThread().getId() + ".. \n");
                Thread.sleep(10000);
                Log.d(TAG, "COMPLETED THE THREAD ID : " + Thread.currentThread().getId() + ".. \n");
            
            catch (Exception e)
            
                e.printStackTrace();
                Log.d(TAG, "EXCEPTION THE THREAD ID : " + Thread.currentThread().getId() + ".. \n");
            
            finally
            
                needWait = false;
                context.notifyAll();
            
        
    

预期输出:

2020-12-30 17:55:46.519 30184-30398/ D/Singular_Processor: RUNNING THE THREAD ID : 6053.. 
2020-12-30 17:55:50.474 30184-30455/ D/Singular_Processor: COMPLETED THE THREAD ID : 6053..
2020-12-30 17:55:56.520 30184-30398/ D/Singular_Processor: RUNNING THE THREAD ID : 6056..
2020-12-30 17:56:00.475 30184-30455/ D/Singular_Processor: COMPLETED THE THREAD ID : 6056.. 

什么是电流输出:

2020-12-30 17:55:46.519  D/Singular_Processor: RUNNING THE THREAD ID : 6053.. 
2020-12-30 17:55:50.474  D/Singular_Processor: RUNNING THE THREAD ID : 6056.. 
2020-12-30 17:55:56.520  D/Singular_Processor: COMPLETED THE THREAD ID : 6053.. 
2020-12-30 17:56:00.475  D/Singular_Processor: COMPLETED THE THREAD ID : 6056.. 

是否有任何错误:

一点也不,因为所有的语法都是正确的。为什么android不能等待几秒钟才能完成线程类上下文的完全锁定对象上已经运行和同步的方法,这让我很担心。我希望我能在这里得到一些想法。谢谢大家。

【问题讨论】:

【参考方案1】:

如果您从同一服务启动Singular_Processor,您需要在所有Singular_Processor 线程之间共享needWait。一种可能的解决方案是将其放在服务本身中,因为您在相同的上下文中同步并使用needWait,它是Singular_Processor 类的不同实例的字段。

【讨论】:

亲爱的你在标准 java 同步器上提供的链接,如果我实现它,它将阻塞主服务 20 秒,我的服务是广播接收器,android 允许广播接收器最多运行 5秒 而且我没有启动 Singular_Processor 两次,它的自然 java 线程趋势,它产生一个新的线程 你在说什么倾向?您只启动一个线程一次,但在日志中,您有两个不同的线程。这意味着Singular_Processor 被启动了两次。 我编辑了答案,对不起,我没有理解真正的问题。 我不能将 needWait 放在服务中,因为服务是一个广播接收器,它会多次停止自身, needWait 不会保证每次都可用。一种方法是在 Runnable 中使用 ATOMIC needWait ,但它也没有按要求工作【参考方案2】:

Thread.sleep() 不会释放同步锁。查看它的 javadoc:

The thread does not lose ownership of any monitors.

因此,只有一个线程可能会进入您的同步块。

【讨论】:

现在看,我的意思是它必须这样做,你也可以在你自己的编译器上交叉检查运行。哈哈。我很高兴你花时间帮助我。多谢兄弟。未来的美好时光【参考方案3】:

在 SO 上为该问题的未来访问者发布自己问题的答案

线程类:

class Singular_Processor extends Thread

    private static final String TAG = "Singular_Processor";
    final Context context;

    Singular_Processor(Context context)
    
        this.context = context;
    

    @Override
    public void run()
    
        try
        
            Log.d(TAG, "run: starting " + Thread.currentThread().getId() + ".. \n");
            doNotDisturbMe();
        
        catch (Exception e)
        
            e.printStackTrace();
        
    

    private static synchronized void doNotDisturbMe()
    
        try
        
            Log.d(TAG, "RUNNING THE THREAD ID : " + Thread.currentThread().getId() + ".. \n");
            Thread.sleep(10000);
            Log.d(TAG, "COMPLETED THE THREAD ID : " + Thread.currentThread().getId() + ".. \n");
        
        catch (Exception e)
        
            e.printStackTrace();
            Log.d(TAG, "EXCEPTION THE THREAD ID : " + Thread.currentThread().getId() + ".. \n");
        
    

调用场景:

无论您是在任何时间间隔以任何频率和从项目中的任何位置启动单个线程还是多个线程......就像我的情况下从广播接收器如下 -

final Singular_Processor singularProcessor = new Singular_Processor(this);
singularProcessor.start();

无论上面的行被调用多少次,以及该线程的实例被创建了多少......

    static method 永远不会为类的特定实例或线程实例创建。 由于我创建了static synchronised,所有线程实例都会运行它们自己实例的方法并感到震惊,哦,我正在调用的方法也是静态和同步的。 个人threads are so smart and intelligent 足够我什至不需要wait 任何人,也不需要打扰notify 任何人或notify all

预期输出:

2020-12-30 22:31:07.856 7866-8309/MyPackage D/Singular_Processor: run: starting 7014.. 
2020-12-30 22:31:07.856 7866-8309/MyPackage D/Singular_Processor: RUNNING THE THREAD ID : 7014.. 
2020-12-30 22:31:11.285 7866-8389/MyPackage D/Singular_Processor: run: starting 7016.. 
2020-12-30 22:31:17.857 7866-8309/MyPackage D/Singular_Processor: COMPLETED THE THREAD ID : 7014.. 
2020-12-30 22:31:17.858 7866-8389/MyPackage D/Singular_Processor: RUNNING THE THREAD ID : 7016.. 
2020-12-30 22:31:27.859 7866-8389/MyPackage D/Singular_Processor: COMPLETED THE THREAD ID : 7016.. 

【讨论】:

以上是关于Java 线程和同步方法未按要求执行的主要内容,如果未能解决你的问题,请参考以下文章

Java线程:线程的同步与锁

Java 多线程 同步和异步

Java 并发 线程同步

Java多线程_同步工具CyclicBarrier

java多线程——锁机制synchronized(同步方法)

java加锁与同步方法