Blocked when sending to unlimited LinkedBlockingQueue if there is no receiver?

I have a simple program to generate input for CRC32, which output a number ending in 123456 (in hexadecimal format). It works in a workflow (the next step is to create multiple workflows). The worker thread sends the results to the q queue.

 import java.util.*; import java.util.concurrent.*; import java.util.zip.*; class A { static final BlockingQueue<List<Byte>> q = new LinkedBlockingQueue<List<Byte>>(); static { new Thread() { public void run() { System.out.println("worker thread starting"); int len = 1; byte[] a = new byte[32]; for (int i =0; i < 32; i++) a[i]=-128; while (true) { CRC32 crc = new CRC32(); crc.update(a, 0, len); long x = crc.getValue(); if ((x & 0xffffff) == 0x123456) { System.out.println("HA " + Arrays.toString(a) + "; " + x); List<Byte> l = new LinkedList<Byte>(); for (int i = 0; i < a.length; i++) l.add(a[i]); System.out.println("A"); q.add(l); System.out.println("B"); // never reaches here } // generate next guess boolean c = true; for (int i = 0; i < len && c; i++) { c = ++a[i] == -128; if (c) if (i + 2 > len) len = i + 2; } } } }.start(); } // for stats: amount of inputs found per interval static long amount = 3; static long interval; static { // record an initial value for interval, so any code using // it doesn't have to have a special case to check whether // it initialized long start = System.currentTimeMillis(); while (q.size() != amount); interval = System.currentTimeMillis() - start; } public static void main(String[] args) { System.out.println("main"); } } 

For some reason it gets stuck:

 $ javac A.java && java A worker thread starting HA [-49, 72, 73, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128]; 1376924758 A 

The worker thread is explicitly blocked when sent to the queue ( q.add(l) ), otherwise, "B" will be printed to the console. If I comment on a line reading from a queue ( while (q.size() != amount) ), it no longer gets stuck. I thought this behavior is not possible for an unlimited queue (if it does not already have 2147483647 elements). This is not a SynchronousQueue , so queuing should work regardless of whether any thread is receiving from it. Actually this behavior seems to be the opposite of SynchronousQueue : sending only works if there is no receiver .

Why is the workflow blocked when trying to queue?

+4
source share
1 answer

It is locked onto synchronized(A.class) not in the queue.

When the main thread starts, it loads class A. To do this, it synchronizes the class itself to efficiently load the class. When you start a new thread and try to access the queue, it will try to load the class (since the class did not complete loading due to busy rotation in the second static block). Now that the first thread has a synchronized class lock, the second thread will sit on the class monitor until the first thread has a second static (busy revolution).

Run the program and kill 3 to see a dump of the stream. You will notice that the monitor is in the classroom and not in the queue.

I will try to illustrate this.

 Thread-1 Load Class A synchronized(A.class){ static: create new Thread (call it Thread-2) static: busy spin while (q.size() != amount); } Thread-2 (after first static) run(){ Aq Load Class A synchronized(A.class){ //block until Thread-1 releases the lock Aqadd(..); } } 
+4
source

Source: https://habr.com/ru/post/1489119/


All Articles