簡體   English   中英

Java Scheduled Executor線程進入等待狀態

[英]Java Scheduled Executor Threads going into Waiting State

因此,我正在嘗試使用兩個自定義線程以及計划的線程執行器來實現從Java客戶端到Go服務器的基本異步消息傳遞協議。 因此,我啟動了一個從Java客戶端到Go服務器的TCP套接字,並在兩側設置了讀寫緩沖區。

Writer線程將與每個請求相對應的唯一ID保存到Redis服務器中,並在TCP套接字上使用PrintWriter寫入請求。

WriterThread

public class WithdrawRequestWriter extends Thread {

    private static final int START_ACCOUNT_NO = 1;
    private static final int END_ACCOUNT_NO = 2_000;
    private static final int AMOUNT_TO_WITHDRAW = 100;

    private PrintWriter writer;
    private Jedis jedis;

    public WithdrawRequestWriter(PrintWriter writer, Jedis jedis) {
        this.writer = writer;
        this.jedis = jedis;
    }

    @Override
    public void run() {
        int i = 0;
        for (int accountNo = START_ACCOUNT_NO; accountNo <= END_ACCOUNT_NO; accountNo++) {
            String uniqueId = UUID.randomUUID().toString();
            if (jedis.set(uniqueId, String.valueOf(accountNo), "NX", "EX", 10) != null) {
                writer.write(uniqueId + " " + accountNo + " " + AMOUNT_TO_WITHDRAW + "\n");
                writer.flush();
            } else {
                System.err.println("Setting of UUID in redis failed: " + uniqueId);
            }
        }
    }
}

同樣,讀取器線程等待服務器的響應。 一旦收到一個,它就與Redis中的唯一ID相匹配,並將它們標記為完成(成功/失敗)。

ReaderThread

public class WithdrawRequestReader extends Thread {

    private BufferedReader reader;
    private Jedis jedis;


    public WithdrawRequestReader(BufferedReader reader, Jedis jedis) {
        this.reader = reader;
        this.jedis = jedis;
    }

    @Override
    public void run() {
        String response;
        while (true) {
            try {
                if ((response = reader.readLine()) != null) {
                    String[] tokenizedResponse = response.split(" ");
                    System.out.println("Response is: " + response);
                    String value = jedis.get(tokenizedResponse[0]);
                    if (value != null) {
                        System.out.println("Request Token: " + tokenizedResponse[0]
                                + " | Status: " + tokenizedResponse[1]
                                + " | Account: " + tokenizedResponse[2]
                                + " | Amount: " + tokenizedResponse[3]
                                + " | Remaining Balance: " + tokenizedResponse[4]
                                + " | ResponeStr: " + tokenizedResponse[5]);
                    }
                } else {
                    System.out.println("Waiting for response...");
                }
            } catch (IOException ex) {
                ex.printStackTrace();
                System.exit(3);
            }
        }
    }
}

主線

public class TestClient {

    private static final String HOSTNAME = "localhost";
    private static final int PORT = 12410;

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

        Socket socket = new Socket(HOSTNAME, PORT);
        PrintWriter writer = new PrintWriter(socket.getOutputStream());
        BufferedReader reader = new BufferedReader(new InputStreamReader(socket.getInputStream()));
        Jedis jedis = new Jedis("localhost");

        ScheduledExecutorService scheduledExecutorService = Executors.newScheduledThreadPool(2);
//        ScheduledExecutorService scheduledExecutorService = Executors.newSingleThreadScheduledExecutor();
        WithdrawRequestReader readerThread = new WithdrawRequestReader(reader, jedis);
        WithdrawRequestWriter writerThread = new WithdrawRequestWriter(writer, jedis);
        scheduledExecutorService.schedule(writerThread, 0, TimeUnit.MILLISECONDS);
        scheduledExecutorService.schedule(readerThread, 0, TimeUnit.MILLISECONDS);
    }
}

當我使用singlePoolThreadExecutor時,任務將按順序執行(如預期的那樣),一切都會順利進行。 但是,當我將threadPoolExecutor與兩個線程一起使用時,經過幾次讀寫操作,它們會無限期地進入等待狀態。 我從網上提供的免費工具中檢查了是否存在死鎖,但沒有任何幫助。 當它們被卡住時,下面是線程轉儲。

線程轉儲

Full thread dump Java HotSpot(TM) 64-Bit Server VM (9.0.4+11 mixed mode):

"DestroyJavaVM" #16 prio=5 os_prio=31 tid=0x00007f974e06d000 nid=0x2503 waiting on condition [0x0000000000000000]
   java.lang.Thread.State: RUNNABLE

"pool-1-thread-2" #15 prio=5 os_prio=31 tid=0x00007f974e06c000 nid=0x6003 waiting on condition [0x000070000c819000]
   java.lang.Thread.State: WAITING (parking)
    at jdk.internal.misc.Unsafe.park(java.base@9.0.4/Native Method)
    - parking to wait for  <0x0000000747cf64b0> (a java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject)
    at java.util.concurrent.locks.LockSupport.park(java.base@9.0.4/LockSupport.java:194)
    at java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject.await(java.base@9.0.4/AbstractQueuedSynchronizer.java:2062)
    at java.util.concurrent.ScheduledThreadPoolExecutor$DelayedWorkQueue.take(java.base@9.0.4/ScheduledThreadPoolExecutor.java:1119)
    at java.util.concurrent.ScheduledThreadPoolExecutor$DelayedWorkQueue.take(java.base@9.0.4/ScheduledThreadPoolExecutor.java:848)
    at java.util.concurrent.ThreadPoolExecutor.getTask(java.base@9.0.4/ThreadPoolExecutor.java:1092)
    at java.util.concurrent.ThreadPoolExecutor.runWorker(java.base@9.0.4/ThreadPoolExecutor.java:1152)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(java.base@9.0.4/ThreadPoolExecutor.java:641)
    at java.lang.Thread.run(java.base@9.0.4/Thread.java:844)

"pool-1-thread-1" #14 prio=5 os_prio=31 tid=0x00007f974e8a9800 nid=0x5e03 waiting on condition [0x000070000c716000]
   java.lang.Thread.State: WAITING (parking)
    at jdk.internal.misc.Unsafe.park(java.base@9.0.4/Native Method)
    - parking to wait for  <0x0000000747cf64b0> (a java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject)
    at java.util.concurrent.locks.LockSupport.park(java.base@9.0.4/LockSupport.java:194)
    at java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject.await(java.base@9.0.4/AbstractQueuedSynchronizer.java:2062)
    at java.util.concurrent.ScheduledThreadPoolExecutor$DelayedWorkQueue.take(java.base@9.0.4/ScheduledThreadPoolExecutor.java:1119)
    at java.util.concurrent.ScheduledThreadPoolExecutor$DelayedWorkQueue.take(java.base@9.0.4/ScheduledThreadPoolExecutor.java:848)
    at java.util.concurrent.ThreadPoolExecutor.getTask(java.base@9.0.4/ThreadPoolExecutor.java:1092)
    at java.util.concurrent.ThreadPoolExecutor.runWorker(java.base@9.0.4/ThreadPoolExecutor.java:1152)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(java.base@9.0.4/ThreadPoolExecutor.java:641)
    at java.lang.Thread.run(java.base@9.0.4/Thread.java:844)

"Service Thread" #11 daemon prio=9 os_prio=31 tid=0x00007f974d827000 nid=0xa003 runnable [0x0000000000000000]
   java.lang.Thread.State: RUNNABLE

"Monitor Ctrl-Break" #10 daemon prio=5 os_prio=31 tid=0x00007f974e078800 nid=0x5903 runnable [0x000070000c40d000]
   java.lang.Thread.State: RUNNABLE
    at java.net.SocketInputStream.socketRead0(java.base@9.0.4/Native Method)
    at java.net.SocketInputStream.socketRead(java.base@9.0.4/SocketInputStream.java:116)
    at java.net.SocketInputStream.read(java.base@9.0.4/SocketInputStream.java:171)
    at java.net.SocketInputStream.read(java.base@9.0.4/SocketInputStream.java:141)
    at sun.nio.cs.StreamDecoder.readBytes(java.base@9.0.4/StreamDecoder.java:284)
    at sun.nio.cs.StreamDecoder.implRead(java.base@9.0.4/StreamDecoder.java:326)
    at sun.nio.cs.StreamDecoder.read(java.base@9.0.4/StreamDecoder.java:178)
    - locked <0x0000000747d9ea78> (a java.io.InputStreamReader)
    at java.io.InputStreamReader.read(java.base@9.0.4/InputStreamReader.java:185)
    at java.io.BufferedReader.fill(java.base@9.0.4/BufferedReader.java:161)
    at java.io.BufferedReader.readLine(java.base@9.0.4/BufferedReader.java:326)
    - locked <0x0000000747d9ea78> (a java.io.InputStreamReader)
    at java.io.BufferedReader.readLine(java.base@9.0.4/BufferedReader.java:392)
    at com.intellij.rt.execution.application.AppMainV2$1.run(AppMainV2.java:64)

"Common-Cleaner" #9 daemon prio=8 os_prio=31 tid=0x00007f974e00a000 nid=0xa203 in Object.wait() [0x000070000c30a000]
   java.lang.Thread.State: TIMED_WAITING (on object monitor)
    at java.lang.Object.wait(java.base@9.0.4/Native Method)
    - waiting on <0x0000000747f37610> (a java.lang.ref.ReferenceQueue$Lock)
    at java.lang.ref.ReferenceQueue.remove(java.base@9.0.4/ReferenceQueue.java:151)
    - waiting to re-lock in wait() <0x0000000747f37610> (a java.lang.ref.ReferenceQueue$Lock)
    at jdk.internal.ref.CleanerImpl.run(java.base@9.0.4/CleanerImpl.java:148)
    at java.lang.Thread.run(java.base@9.0.4/Thread.java:844)
    at jdk.internal.misc.InnocuousThread.run(java.base@9.0.4/InnocuousThread.java:122)

"Sweeper thread" #8 daemon prio=9 os_prio=31 tid=0x00007f974d81c000 nid=0x5803 runnable [0x0000000000000000]
   java.lang.Thread.State: RUNNABLE

"C1 CompilerThread2" #7 daemon prio=9 os_prio=31 tid=0x00007f974d81b000 nid=0xa503 waiting on condition [0x0000000000000000]
   java.lang.Thread.State: RUNNABLE
   No compile task

"C2 CompilerThread1" #6 daemon prio=9 os_prio=31 tid=0x00007f974e005000 nid=0xa603 waiting on condition [0x0000000000000000]
   java.lang.Thread.State: RUNNABLE
   No compile task

"C2 CompilerThread0" #5 daemon prio=9 os_prio=31 tid=0x00007f974d81a800 nid=0xa803 waiting on condition [0x0000000000000000]
   java.lang.Thread.State: RUNNABLE
   No compile task

"Signal Dispatcher" #4 daemon prio=9 os_prio=31 tid=0x00007f974e01a800 nid=0x5603 waiting on condition [0x0000000000000000]
   java.lang.Thread.State: RUNNABLE

"Finalizer" #3 daemon prio=8 os_prio=31 tid=0x00007f974d041800 nid=0x4003 in Object.wait() [0x000070000bc75000]
   java.lang.Thread.State: WAITING (on object monitor)
    at java.lang.Object.wait(java.base@9.0.4/Native Method)
    - waiting on <0x0000000747f0d078> (a java.lang.ref.ReferenceQueue$Lock)
    at java.lang.ref.ReferenceQueue.remove(java.base@9.0.4/ReferenceQueue.java:151)
    - waiting to re-lock in wait() <0x0000000747f0d078> (a java.lang.ref.ReferenceQueue$Lock)
    at java.lang.ref.ReferenceQueue.remove(java.base@9.0.4/ReferenceQueue.java:172)
    at java.lang.ref.Finalizer$FinalizerThread.run(java.base@9.0.4/Finalizer.java:216)

"Reference Handler" #2 daemon prio=10 os_prio=31 tid=0x00007f974d040800 nid=0x4103 waiting on condition [0x000070000bb72000]
   java.lang.Thread.State: RUNNABLE
    at java.lang.ref.Reference.waitForReferencePendingList(java.base@9.0.4/Native Method)
    at java.lang.ref.Reference.processPendingReferences(java.base@9.0.4/Reference.java:174)
    at java.lang.ref.Reference.access$000(java.base@9.0.4/Reference.java:44)
    at java.lang.ref.Reference$ReferenceHandler.run(java.base@9.0.4/Reference.java:138)

"VM Thread" os_prio=31 tid=0x00007f974e884000 nid=0x4303 runnable 

"GC Thread#0" os_prio=31 tid=0x00007f974e80d800 nid=0x2a03 runnable 

"GC Thread#1" os_prio=31 tid=0x00007f974e80e800 nid=0x5303 runnable 

"GC Thread#2" os_prio=31 tid=0x00007f974d80c800 nid=0x2b03 runnable 

"GC Thread#3" os_prio=31 tid=0x00007f974d000800 nid=0x2c03 runnable 

"G1 Main Marker" os_prio=31 tid=0x00007f974e835800 nid=0x4803 runnable 

"G1 Marker#0" os_prio=31 tid=0x00007f974d80d800 nid=0x4503 runnable 

"G1 Refine#0" os_prio=31 tid=0x00007f974e80f800 nid=0x4a03 runnable 

"G1 Refine#1" os_prio=31 tid=0x00007f974d80d000 nid=0x4c03 runnable 

"G1 Refine#2" os_prio=31 tid=0x00007f974e80f000 nid=0x4e03 runnable 

"G1 Refine#3" os_prio=31 tid=0x00007f974e806800 nid=0x5003 runnable 

"G1 Young RemSet Sampling" os_prio=31 tid=0x00007f974e810800 nid=0x2f03 runnable 

"VM Periodic Task Thread" os_prio=31 tid=0x00007f974e079800 nid=0x5c03 waiting on condition 

JNI global references: 421

Heap
 garbage-first heap   total 131072K, used 10240K [0x0000000740000000, 0x0000000740100400, 0x00000007c0000000)
  region size 1024K, 11 young (11264K), 0 survivors (0K)
 Metaspace       used 8824K, capacity 9274K, committed 9472K, reserved 1058816K
  class space    used 832K, capacity 927K, committed 1024K, reserved 1048576K

我相信Go服務器不是問題,否則單線程執行器也應該卡住,但不是。 可能是我陷入了僵局,但無法找出確切原因。 有人可以幫忙嗎? 如果您還有其他需要,請告訴我。

代碼的套接字和流部分似乎是正確的。 並行使用套接字的輸入和輸出流是正確的,因為它們是獨立的流。

問題是Jedis組件。 Jedis不是線程安全的。 Jedis文檔說:

您不應該使用來自不同線程的同一實例,因為您會遇到奇怪的錯誤。 有時創建大量的Jedis實例還不夠好,因為這意味着大量的套接字和連接,這也會導致奇怪的錯誤。 單個Jedis實例不是線程安全的!...

重寫代碼是必要的,以便每個線程都有Jedis的私有實例。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM