【问题标题】:How can I lock/unlock resources between threads?如何在线程之间锁定/解锁资源?
【发布时间】:2023-01-11 01:54:23
【问题描述】:

我正在玩代理 API。

我创建了一个这样的 SSLSocket:

try {
    // Crea el socket SSL
    s = (SSLSocket) SSLSocketFactory.getDefault().createSocket("xapi.xtb.com", 5124);
    s.setKeepAlive(true);          
} catch (IOException e) {
    e.printStackTrace();
}

我需要在登录和交易操作中使用该套接字,而且,我还需要每 10 分钟执行一次 ping。

所以我使用线程创建一个线程来登录并启动 ping 循环(最后一个有睡眠(60000))

new Thread(() -> {
        try {
            assert s != null;
            BufferedWriter pingOut = new BufferedWriter(new OutputStreamWriter(s.getOutputStream()));
            BufferedReader pingIn = new BufferedReader(new InputStreamReader(s.getInputStream()));
            // crea un bucle while infinito

            while (true) {
                pingOut.write(
                        "{\"command\":\"ping\"}");
                pingOut.flush();
                pingIn.readLine();
                Thread.sleep(10000);
            }
        } catch (IOException  ex) {
            ex.printStackTrace();
        } catch (InterruptedException e1) {
            e1.printStackTrace();
        }
    }).start();

然后,另一个线程在单击按钮时启动,该按钮发送一个类似的字符串,但使用交易选项且没有循环,该线程(交易)在每次交易操作后被终止。

我的主要问题是,有时 bufferedRead 会混合来自两个线程的响应,所以我想到了使用锁、等待和通知,但这不起作用,ping 循环正在绑架资源(sslsocket)锁定对另一个线程(或将来,线程)

那么,我怎样才能实现它以使用“s”,同时避免混合响应呢? (有时在打印tradeIn.readline()时,得到了pingIn.readline()的回复内容。

或者,如果有另一种方式来获得避免混合的响应,也欢迎

添加同步尝试代码:

Object lock = new Object();

new Thread(() -> {
        synchronized (lock) {
            try {
                assert s != null;
                BufferedWriter pingOut = new BufferedWriter(new OutputStreamWriter(s.getOutputStream()));
                BufferedReader pingIn = new BufferedReader(new InputStreamReader(s.getInputStream()));
                // crea un bucle while infinito

                while (true) {
                    pingOut.write(
                            "{\"command\":\"ping\"}");
                    pingOut.flush();
                    pingIn.readLine();
                    Thread.sleep(10000);
                }
            } catch (IOException  ex) {
                ex.printStackTrace();
            } catch (InterruptedException e1) {
                e1.printStackTrace();
            }

            lock.notify();
        }
    }).start();

第二个线程:

 synchronized (lock) {
    try {
        lock.wait();
    } catch (InterruptedException e1) {
        e1.printStackTrace();
    }
}
try {
    assert s != null;
    BufferedReader tradeIn = new BufferedReader(new InputStreamReader(s.getInputStream()));
    BufferedWriter tradeOut = new BufferedWriter(new OutputStreamWriter(s.getOutputStream()));
    tradeOut.write(
            "{\"command\":\"tradeTransaction\",\"arguments\":{\"tradeTransInfo\":{\"cmd\":0,\"customComment\":\"Some text\",\"expiration\":3462006335000,\"offset\":0,\"order\":0,\"price\":10000.0,\"sl\":9420.0,\"symbol\":\"US100\",\"tp\":0.0,\"type\":0,\"volume\":0.02}}}");
    tradeOut.flush();
    twoperacion.setText(tradeIn.readLine());
} catch (IOException ex) {
    ex.printStackTrace();
}

【问题讨论】:

  • 您是否尝试用谷歌搜索有关“线程同步”的任何信息?
  • 是的,一些尝试涉及同步(锁定)、执行程序、并发执行程序……但我(讽刺地)被锁定了 xD
  • 但是您没有显示任何同步尝试。
  • 它们是随时间演变的替代解决方案。例如,ReadWriteLock
  • 你看,它就在那里 - 你在评论中显示的代码完全无效,并且在你的情况下几乎不会同步任何内容,因为它必须 notify/notifyAll 必须与 wait 一起使用才能按预期工作。

标签: java api


【解决方案1】:

这是因为这不是等待/通知系统的使用方式。

// first snippet
 synchronized (lock) {

只要此线程的“位置”(它正在执行的内容)在此 synchronized 块的主体内,任何其他线程,如果它命中 synchronized (lock) 语句,将等待.只有一个线程可以“持有锁”。除了一个例外:lock.wait()

// still first snippet
Thread.sleep(10000);

在任何 synchronized 块内调用 sleep 实际上肯定是一个严重的错误。你还拿着lock- 10 秒后,没有其他线程可以输入synchronized (lock)。我非常怀疑这就是你想要的。停止输入synchronized,然后再拿起它。

// second snippet
lock.wait();

wait 是唯一的:它释放锁,然后等待通知。一旦收到通知,它将重新获取锁(根据定义,这将是不可能的;通知的任何线程仍然持有它,因为你不能调用lock.notify(),除非你在synchronized(lock)内,因此,另一个线程有锁,而带有wait()命令的线程不能重新获取)。这将需要一些时间(另一个线程需要先退出同步块)。

然后它会继续。

那么至关重要的是,执行通知的线程确实需要在某个时候停止在同步块中.

因此,在简单计时器上运行的通知代码块的一般“外观”如下所示:

while (running) {
  synchronized (lock) {
    // Do relevant stuff
    lock.notify();
  }
  Thread.sleep(10000);
}

注意我们如何不要睡觉时持有那个同步锁。

通常,您最好使用 java.util.concurrent 包中的相关内容。哪一个可能是一把锁,但更常见的是一个闩锁,或者一个集合,或者包装必须提供的许多很多东西中的任何其他东西。我不太清楚您要解决的潜在问题,所以我不确定要推荐什么。

【讨论】:

  • 我很笨,你的权利,我在睡觉后通知......谢谢你。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-01-04
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-01-21
  • 1970-01-01
相关资源
最近更新 更多