`
卒子99
  • 浏览: 75387 次
  • 性别: Icon_minigender_1
  • 来自: 杭州
社区版块
存档分类
最新评论

在Linux下多线程的问题

    博客分类:
  • Java
阅读更多
最近做的程序出现了一个多线程的问题,肯定是同步引起的,但是我个人还是不太理解,因为同样一段代码在Windows下运行正常,在Linux下就处理一堆问题了。

程序思想是这样子的,有多个任务需要处理,每次主线程处理一个任务,并把这个任务分成多个子任务让子线程去处理。在主线程中启动多个子线程去做事情,并注册自己。主线程就不断的检查是所有线程已经注销了,子线程做完事情后,会向主线程销自己,然后结束。

代码如下:

public class TaskDispatchController
{
    Set threadSet = new HashSet();
    /**
    *  启动子线线程做事情
    */
    private void startThread()
    {
        //重用线程对象
        ImportThread[] thread = importTool.getImportThread();
        threadList = new ArrayList(thread.length);
        for (int i = 0; i < thread.length; i++)
        {
            ImportThread impThread = thread[i];
            //子线程注册自己
            threadSet.add(impThread);
            impThread.setController(this);
            new Thread(impThread).start();
        }
        checkQuite();
    }
    
    /**
    *  注销自己,并唤醒主线程检查是否可以退出
    */
    public synchronized void unregister(ImportThread thread)
    {
       threadSet.remove(thread);
       notifyAll();
    }

    /**
    *
    */
    private synchronized void checkQuite()
    {
        try
        {
            while (!threadSet.isEmpty())
            {
                wait();
            }
            backThread();
        }
        catch (InterruptedException e)
        {
            throw new ThreadOperationException("main thread exception", e);
        }
        finally
        {
            close();
        }
    }
}

public class ImportThread
{
    TaskDispatchController  taskDispatchController = null;
    public void setController(TaskDispatchController  taskDispatchController )
    {
         this.taskDispatchController = taskDispatchController ;
    }
     public void run()
     {
	if (taskDispatchController == null)
	{
	    return;
	}
         //做某事情
         [b]taskDispatchController.doXXX();[/b]	
         while (true)
	{
	    // do something
         }
         //执行完事情后结束
	release();
     }
     
     
     private void release()
     {
	if (taskDispatchController != null)
	{
	    taskDispatchController .unregister(this);
	}
         [b]taskDispatchController == null;[/b]    
     }
}





这段代码在Windows下,双核CPU的环境中做事不会出现错误,且可以启动多个子线程。但在Linux环境下,就启动一个子线程就会出问题,会出现死锁,并且是销在TaskDispatchController的startThread方法,感到很奇怪。

解决方法:随后,我将startThread线程,并标记为同步,并且要所有子线程启动后,子线程才能注销自己。以避免子线程跑得太快了,就结束自己了(这是领导认为的问题所在,但我个人不这么认为,看代码就明白了)。

修改了之后仍然出现死锁。原因是:在子线程run中调用taskDispatchController.doXXX()的时候报NullPointerException,导致子线程没有注销自己,主线程处于一直等待状态。

解决方法:因为我在线程结束的时候将taskDispatchController = null了(也不知道当时是怎么考虑的,其实没有必要设置为null),所以我将release方法中这一行删去。
并修改TaskDispatchController.unregister方法
  public synchronized void unregister(ImportThread thread)
  {
       threadSet.remove(thread);
       thread.setController(null);
       notifyAll();
  }


现在程序在Linux下能正常运行,但其中的原因还是不得而知,希望哪位指点指点
分享到:
评论
6 楼 卒子99 2008-09-12  
start方法就加了一个synchronized,上面没有写出来,不过现在看,当时一年前写的东西是有很多问题,确实多线程太复杂了,出错就报一些莫名其妙的问题,调试起来也很麻烦。看来要在设计的时候,特别注意这些问题,哈哈一条,不得已就不要用多线程了
5 楼 dennis_zane 2008-09-12  
从你的代码中没有看出为什么在同步后出现空指针,不过你的代码还是有问题,对startedAll变量的修改没有同步,也就是startThread方法需要同步,这个可能是你弄错了。jvm的不同实现,肯定依赖于平台,java对线程安全性的保证是基于java内存模型的,符合java内存模型的代码在各个平台上可以做到的一致,如果一开始就是错误的,在不同平台出现莫名其妙的问题在所难免。
4 楼 卒子99 2008-09-12  
可能我表述的有点问题,每一次我都使用缓存的ImportThread对象,而每次执行一个任务都是new 的一个新的TaskDispatchController(呵呵设计上还是有点问题)
所以在ImportThreadn的当前任务结束的时候,将它引用的TaskDispatchController对象置为null,我觉得是这儿引起的NullPointerException
private void release()   
{   
    if (taskDispatchController != null)   
    {   
        taskDispatchController .unregister(this);   
    }   
    <STRONG>taskDispatchController == null;</STRONG>       
}


修改之后为:
class ImportThread

private void release()   
{   
    if (taskDispatchController != null)   
    {   
        taskDispatchController .unregister(this);   
    }      
}

TaskDispatchController
     /**    
    *  注销自己,并唤醒主线程检查是否可以退出    
    */     
    public synchronized void unregister(ImportThread thread)      
    {     
       try  
       {   
           while(!startedAll)   
           {   
               wait();   
           }   
       }   
       catch(InterruptedException e)   
       {   
           // doNothing   
       }
       //将引用的controller置为null
       threadSet.setController(null);    
       threadSet.remove(thread);      
       notifyAll();      
    }  


如此修改后,也不会有问题了。到底这多线程在linux和windows是上运行方式有什么差异呢,这是我最知道的问题
3 楼 卒子99 2008-09-12  
dennis_zane 写道
同步后出现的空指针问题,想了下,我的理解还是错误,也没有复现你的场景。你说“并且要所有子线程启动后,子线程才能注销自己”,不知道怎么修改的,我想看看,可能是你修改的部分出问题了。

我是加了一个变量 来控制的

voliate boolea staredAll = false;
Set threadSet = new HashSet();   
    /**  
    *  启动子线线程做事情  
    */  
    private void startThread()   
    {   
        //重用线程对象   
        ImportThread[] thread = importTool.getImportThread();   
        threadList = new ArrayList(thread.length);   
        for (int i = 0; i < thread.length; i++)   
        {   
            ImportThread impThread = thread[i];   
            //子线程注册自己   
            threadSet.add(impThread);   
          impThread.setController(this);   
          new Thread(impThread).start();   
        }
        startedAll= true;   
        checkQuite();   
    }   
       
    /**  
    *  注销自己,并唤醒主线程检查是否可以退出  
    */  
    public synchronized void unregister(ImportThread thread)   
    {  
       try
       {
           while(!startedAll)
           {
               wait();
           }
       }
       catch(InterruptedException e)
       {
           // doNothing
       } 
       threadSet.remove(thread);   
       notifyAll();   
    }   



呵呵,当时做的时候还不怎么了解Concurrent,现在已经改了代码实现了,用上了这些feature,不过我不明白为什么在Liunx下面的运行,跑一个线程也会有问题,我猜是linux下的线程调度不太一样,想知道其中的原由,还请指点
2 楼 dennis_zane 2008-09-11  
而且我觉的你的代码完全可以用CountDownLatch+ExecutorService改写,更漂亮,更简洁。
1 楼 dennis_zane 2008-09-11  
第一次遇到的问题并不是什么死锁,是主线程wait没有被唤醒,问题在于你的HashSet在添加元素的时候没有加锁,HashSet不是线程安全的,你remove和判断isEmpty都记的synchronized,怎么add的时候却忘记呢,导致isEmpty返回的值不是真实值,主线程一直没有被唤醒,特别是在线程多并发大的情况下。你可以试试在windows上开5000个线程试试,在我机器上马上复现了你的现象。因此你的领导说startThread加锁同步是没错的,就是解释错了。

同步后出现的空指针问题,想了下,我的理解还是错误,也没有复现你的场景。你说“并且要所有子线程启动后,子线程才能注销自己”,不知道怎么修改的,我想看看,可能是你修改的部分出问题了。

相关推荐

    Linux多线程服务端编程:使用muduo+C网络库

    Linux多线程服务端编程:使用muduo+C网络库.pdf Linux多线程服务端编程:使用muduo+C网络库.pdfLinux多线程服务端编程:使用muduo+C网络库.pdfLinux多线程服务端编程:使用muduo+C网络库.pdfLinux多线程服务端编程:...

    Linux下C语言多线程编程实例

    Linux 下的多线程编程是一种非常重要的技术,在实际应用中有非常广泛的应用范围。多线程编程可以大大提高程序的执行效率和响应速度。但是,多线程编程也存在一些复杂性,例如线程之间的同步和互斥控制等问题。 在 ...

    linux多线程编程.pdf

    Linux多线程编程不仅需要对pthread库函数有深入的理解,还需要掌握线程同步和通信的机制,比如互斥锁(mutexes)、条件变量(condition variables)等,以便协调多个线程对共享资源的访问,防止数据竞争和条件竞争等...

    Linux系统下的多线程编程入门.pdf

    在Linux系统下进行多线程编程是开发高效并发应用程序的关键技术之一。本文将深入探讨Linux环境中的多线程概念、创建与管理线程的方法、线程同步与通信机制,以及多线程编程中可能遇到的问题和解决策略。 一、多线程...

    Linux下的多线程编程.pdf

    "Linux下的多线程编程" Linux下的多线程编程是一种高效的程序设计方法,它可以将一个程序的任务划分为多个部分,每个部分是一个顺序控制流。多线程编程可以实现并行计算,高效利用多处理器,并且具有许多优点,如...

    linux下多线程编程

    在 Linux 下编写多线程程序时,需要了解 pthread 的基本概念和函数。pthread_t 是一个线程的标识符,typedef unsigned long int pthread_t; 它在头文件 /usr/include/bits/pthreadtypes.h 中定义。 pthread_create ...

    Linux多线程服务端编程

    Linux多线程服务端编程是陈硕大神的一本linux服务端开发实战书籍。

    Linux多线程服务端编程,高清无水印!~

    Linux多线程服务端编程,高清无水印!~

    linux下多线程模拟实验

    在这个"Linux下多线程模拟实验"中,我们将深入探讨如何使用C语言在Linux环境下实现生产者-消费者问题,这是一个经典的线程同步问题。 生产者-消费者问题是多线程编程中的一个经典案例,主要用于演示如何通过共享...

    linux_code.rar_linux 多线程_linux 线程_多线程编程

    在Linux系统中,多线程编程是实现高效并发执行任务的一...总的来说,这份压缩包为学习Linux多线程编程提供了宝贵的实践材料,通过深入研究这些源码,你可以更好地理解和掌握多线程在Linux环境中的工作原理和最佳实践。

    Linux下基于多线程的服务器程序设计.pdf

    为了解决这些问题,文章介绍了一种基于Linux下的多线程服务器程序设计方法。 多线程服务器程序设计的优点是可以解决传统服务器工作方式的三个缺点。首先,创建线程比创建进程快10~100倍,能快速地响应客户请求。...

    Linux下多线程编程详解

    Linux下多线程编程是操作系统领域中的一个重要技能,它允许在单个进程内执行多个线程来并行处理任务。这种编程模式与传统的多进程编程相比,具有更高的效率,因为线程之间的切换比进程间的切换要快,且它们共享同一...

    Linux多线程编程手册

    总体来说,Linux多线程编程手册是一个关于在Linux环境下使用多线程API进行编程的全面指南。对于希望构建高性能、高响应速度应用程序的开发者来说,这是一份宝贵的资源。手册中不仅详细介绍了多线程编程的理论知识,...

    嵌入式软件开发技术:第5章 嵌入式Linux多线程编程.ppt

    嵌入式Linux多线程编程 嵌入式Linux多线程编程是嵌入式系统开发中的一种重要技术,能够提高系统的效率和响应速度。本章节将详细介绍嵌入式Linux多线程编程的基本概念、线程的创建、同步和互斥、线程属性、多线程...

    Linux c++多线程串口编程demo

    通过这个demo,你可以学习如何在Linux环境下使用C++进行多线程串口编程,理解线程同步的概念,以及如何处理硬件交互。对于理解和应用这些技术,阅读和分析源代码将是至关重要的。同时,这个项目也可以作为进一步研究...

    linux多线程demo

    总结,"linux多线程demo"是一个演示如何在Linux环境下使用多线程的项目,通过CMake进行构建,适用于嵌入式系统,特别是ARM架构。理解和掌握多线程、CMake以及它们在嵌入式Linux中的应用对于开发高效、可靠的嵌入式...

    linux多线程实现矩阵乘法

    linux下多线程实现矩阵乘法,可以对操作系统的线程有更多理解

Global site tag (gtag.js) - Google Analytics