一个生产者多消费者表现

时间:2014-09-09 07:06:50

标签: java multithreading concurrency consumer synchronisation

我的Java程序具有客户端 - 服务器架构。在客户端我创建1条消息并使用10000线程我将其发送到服务器,因为10000客户端同时发送一条消息。在Server类一侧,我有一个固定大小的队列,每个消息首先必须放入这个队列。然后在多个通道(或多个客户端)同时读取消息。如果一个通道(或消费者)读取一条消息,则必须从队列中删除此消息。   但是多个频道不会给我足够的性能而不是一个频道。我认为线程同步问题。我如何优化我的计划?这是我的计划。

İn客户端我有一个可运行的类(我显示类的重要部分)用于发送消息

public void run() 
{  
   pw.println(message+numberofmessage);
}

在主要客户端类

ExecutorService pool = Executors.newFixedThreadPool(axinsayi);
          for(int i=1;i<=countofUser;i++)
          {
            pool.execute(new SendMessagetoServer(pw,message,i));
          }
           pool.shutdownNow(); 

在服务器端,我用

写入队列
public void run() 
{   
    while (true) 
    {   
        try {if(!input.ready()) continue;} 
        catch (IOException ex) {}

        synchronized (queue) 
        {
            while (queue.size() == buffersize) 
            {
                try 
                {queue.wait();} 
                catch (InterruptedException ex){}
            }
            try {line=input.readLine();} 
            catch (IOException ex) {}
            System.out.println("Entered to buffer : " + line);
            queue.add(line);
            queue.notifyAll();
        }
    }
}

读取此缓冲区并使用

发送到Oracle DB消息
public void run() 
{    
    while (true) 
    {
        synchronized (queue) 
        {
            while (queue.isEmpty()) 
            {
                try {queue.wait();} 
                catch (InterruptedException ex) {}
            }
            line=(String)queue.remove();

        // ORACLE DB İnsert part    
            if(conn==null)
           { 
             try { DriverManager.registerDriver(new oracle.jdbc.driver.OracleDriver());
                   conn = DriverManager.getConnection("jdbc:oracle:thin:@localhost:1521:orcl",          "HR", "Ilkinpassword");} 
             catch (SQLException ex) {System.out.println("Connection not created");}
           }
           try {String sql = "insert into hr.info values('"+line+"')";
                ps = conn.prepareStatement(sql);
                ps.executeUpdate();
                System.out.println(line + " inserted to DB");} 
            catch (SQLException ex) {System.out.println(line+"cant inserted to DB");}
            try {ps.close();} 
            catch (SQLException ex) {}
            queue.notifyAll();
        }
    }
}

我使用

创建的多个频道
public void run() 
{ 
    for(int i=1;i<=counntofChannel;i++)
    {
      pool.execute(new WriteFromQueuetoDB(queue));
    }
     pool.shutdownNow();
}

最后在服务器类中,我启动2个线程,其中一个写入缓冲区,另一个创建从Queue读取并写入DB的通道。

public static void main(String ... args) throws Exception 
{
  new Server().FromClienttoBuffer();
  Thread CreteChannel=new Thread(new CreteChannel(queue,kanalsayi),"CreteChannel" );
  CreteChannel.start();
} 

2 个答案:

答案 0 :(得分:1)

可以从同步(队列)块中删除一些内容,因为它们是独立的,因此可以并行执行。

 try {line=input.readLine();} 
            catch (IOException ex) {}
            System.out.println("Entered to buffer : " + line);

以及

// ORACLE DB İnsert part    
    if(conn==null)
   { 
     try { DriverManager.registerDriver(new oracle.jdbc.driver.OracleDriver());
           ...
    queue.notifyAll();

答案 1 :(得分:1)

基本上你需要减少synchronized {}块中出现的代码量(正如@Debasish所指出的那样),并且你与数据库和文件系统的交互阻碍了你发布的锁定queue,阻止其他线程与队列交互。从我所看到的你只需要对队列的“读”和“写”进行同步,但所有其他工作应该在任何同步块之外。

我建议您尝试实施BlockingQueue,这样您就不必自己实现同步。让Java API为您提高效率。

有关提示

,请参阅此SO Post about using a BlockingQueue