有没有办法让Java线程只在初始化时执行某些操作?

有没有办法让Java线程只在初始化时执行某些操作?,java,multithreading,Java,Multithreading,对不起,如果这是基本的,我只是看不到答案。基本上,我使用ThreadPoolExecutor运行几个线程来启动10个线程。我希望每个线程在其生命周期内与服务器建立自己的连接。有可能吗?如果有,我应该把代码放在哪里 示例代码: class DoWork implements Runnable{ protected String[] data = null; public DoWork(String[] data) { // get the data each

对不起,如果这是基本的,我只是看不到答案。基本上,我使用ThreadPoolExecutor运行几个线程来启动10个线程。我希望每个线程在其生命周期内与服务器建立自己的连接。有可能吗?如果有,我应该把代码放在哪里

示例代码:

class DoWork implements Runnable{

    protected String[] data = null; 

    public DoWork(String[] data) {
        // get the data each thread needs to work
        this.data = data;
    }

    public void run() {
        // Do the work here

    }

}
我的理解是,如果工作队列中有项目,那么ThreadPoolExecutor将保持10个线程的活动状态,当工作完成时,它们将死亡。在这个结构中是否有我可以添加连接信息的地方?我不想在DoWork方法中这样做,因为这将为每个工作单元完成。因此,为工作队列中的许多项打开连接,可能有数千项,并且在我尝试时会导致超时。放在类声明和方法之间似乎没有做任何事情,尽管我可能做错了

有什么办法可以做到这一点吗


更新:不是100%需要,但我很好奇是否有办法让它在终止时执行某些操作,这样我就可以关闭与服务器的连接,而不是等待它超时。

您可以使用ThreadLocal来存储每个线程的连接:

public class ConnectionProvider {
    private static final ThreadLocal<Connection> threadLocalConnection = 
         new ThreadLocal<Connection>() {
             @Override 
             protected Connection initialValue() {
                 // TODO create and return the connection
             }
         };

    public static Connection getConnection() {
        return threadLocalConnection.get();
    }
}

或者,如果多个线程可以在不同的时间使用这些连接,则可以创建一个连接池。run方法将从池中获取一个连接,该池将动态创建该连接并将其添加到已创建的连接集中。如果没有可用的连接,则在finally块中将其释放到池中,直到使用完毕。这将使连接可用于任何其他任务。这样做的好处是使所需的连接数可能低于线程池中的线程数。

创建自己的线程工厂,并将其作为参数传递给线程池构造函数。线程工厂创建的线程应覆盖方法运行,如下所示:

public void run() {
  connectToServer();
  super.run();
}

问题是,谁以及如何使用这种联系?如果您的意思是提供给线程池的每个作业都应该使用由其运行的线程创建的连接,则将该连接另存为ThreadLocal。

改编自我在

这将创建一个连接池,您可以从中进行绘制。这将防止每个线程的连接上下移动。然而,只有在哪个线程使用哪个连接无关紧要的情况下,这才有效。如果这真的很重要,那么您必须修改此代码或使用其他人建议的ThreadLocal,并在线程死亡时将其挂接

当一个新的工作项排队时,线程会向连接池请求一个连接。如果一个不可用,它将创建一个新的。如果有可用的连接,它将验证连接是否仍然有效,然后返回该对象。工作项完成后,可以将其返回到连接池

public class StackOverflow_10037379_jdk6 {

    private static Logger sLogger = Logger.getLogger(StackOverflow_10372827_jdk6.class.getName());           

    public static class ConnectionPoolableObjectFactory extends BasePoolableObjectFactory<Connection> {

        public ConnectionPoolableObjectFactory() {

        }

        @Override
        public Connection makeObject() throws Exception {                
            Connection connection = // createConnection
            return connection;
        }

        @Override
        public boolean validateObject(Connection connection) {
            return connection.isValid();
        }

        @Override
        public void destroyObject(Connection connection) throws Exception {
            connection.close();
        }

        @Override
        public void passivateObject(Connection connection) throws Exception {

        }
    }

    public static class WorkItem implements Runnable {

        private ObjectPool<Connection> mPool;
        private String mWork;

        public CLIWorkItem(ObjectPool<Connection> pool, String work) {
            mPool = pool;
            mWork = work;
        }

        @Override
        public void run() {
            Connection connection = null;
            try {
                connection = mPool.borrowObject();
                // do stuff with connection
            } catch (Exception ex) {
                sLogger.log(Level.SEVERE, null, ex);
            } finally {
                if (connection != null) {
                    try {
                        // Seriously.. so many exceptions.
                        mPool.returnObject(connection );
                    } catch (Exception ex) {
                        sLogger.log(Level.SEVERE, null, ex);
                    }
                }
            }
        }
    }

    public static void main(String[] args) throws Exception {

        // Change the 5 to 20 in your case. 
        ObjectPool<Connection> pool =
                new GenericObjectPool<Connection>(
                new ConnectionPoolableObjectFactory(), 5);

        BlockingQueue<Runnable> queue = new ArrayBlockingQueue<Runnable>(100, true);

        ThreadPoolExecutor executor = new ThreadPoolExecutor(20, 20, 1, TimeUnit.HOURS, queue);

        // print some stuff out.
        executor.execute(new WorkItem(pool, "Message 1\r\n"));
        executor.execute(new WorkItem(pool, "Message 2\r\n"));
        executor.execute(new WorkItem(pool, "Message 3\r\n"));
        executor.execute(new WorkItem(pool, "Message 4\r\n"));
        executor.execute(new WorkItem(pool, "Message 5\r\n"));
        executor.execute(new WorkItem(pool, "Message 6\r\n"));
        executor.execute(new WorkItem(pool, "Message 7\r\n"));
        executor.execute(new WorkItem(pool, "Message 8\r\n"));
        executor.execute(new WorkItem(pool, "Message 9\r\n"));
        executor.execute(new WorkItem(pool, "Message 10\r\n"));
        executor.execute(new WorkItem(pool, "Message 11\r\n"));

        executor.shutdown();
        executor.awaitTermination(4000, TimeUnit.HOURS);

        pool.close();
    }
}

仅仅使用连接池不是更容易吗?然后,每个任务都将在启动时从池中检索连接,并在完成时返回连接。这样,您就不必创建比线程更多的连接,并且可以在所有任务完成后轻松销毁连接池及其所有连接。

为什么不在构造函数参数中传递信息?@HovercraftFullOfEels这不就是为每个工作项创建新连接吗?抱歉,如果我关闭了,我以前没有使用过它们。你只是想重用连接,还是必须是使用特定连接的特定线程?@AndrewFinnell现在我只是想比较一下。我最初将连接信息传递给每个线程,但是阻塞太多了。所以我创建了一个objectpool,但我想将其与每个线程都有自己的专用连接进行比较,并分析其差异。这不是一个很好的解决方案。他必须手动跟踪踏板何时消失,然后调用。删除并清理连接。游泳池中的一根线可能会消失,这是一个正确的说法。我不知道所有的要求,甚至不知道OP谈论的是哪种连接。但是这个想法是为了展示如何将一个对象与一个线程相关联。@AndrewFinnell他不必手动删除它,垃圾收集器会为他做这件事。然而,他将不得不清理连接。@Jeffrey Hum,这是真的。如果连接可以无限期地保持活动状态,他可以在代理对象上实现一个终结器,该代理对象保存对连接的引用。然后在终结器中处理连接。但这违反了有关终结器的规则。