Hola, hemos encontrado la solución a tu búsqueda, continúa leyendo y la obtendrás más abajo.
Solución:
Como dijiste que querías “un mapeo de memoria compartido entre subprocesos”, no existe tal problema en absoluto, ya que el mapeo de memoria no se ve afectado por el cierre de un FileChannel
. De hecho, es una buena estrategia cerrar el canal lo antes posible para reducir los recursos que tiene la aplicación.
P.ej
static volatile boolean running = true;
public static void main(String[] args) throws IOException {
Path name = Paths.get("delete.me");
MappedByteBuffer mapped;
try(FileChannel fc1 = FileChannel.open(name, READ,WRITE,CREATE_NEW,DELETE_ON_CLOSE))
mapped = fc1.map(FileChannel.MapMode.READ_WRITE, 0, 4096);
Thread thread1 = new Thread(() ->
LockSupport.parkNanos(TimeUnit.MILLISECONDS.toNanos(50));
while(running && !Thread.interrupted())
LockSupport.parkNanos(TimeUnit.MILLISECONDS.toNanos(100));
byte[] b = new byte[5];
mapped.position(4000);
mapped.get(b);
System.out.println("read "+new String(b, StandardCharsets.US_ASCII));
);
thread1.setDaemon(true);
thread1.start();
Thread thread2 = new Thread(() ->
byte[] b = "HELLO".getBytes(StandardCharsets.US_ASCII);
while(running && !Thread.interrupted())
LockSupport.parkNanos(TimeUnit.MILLISECONDS.toNanos(100));
mapped.position(4000);
mapped.put(b);
System.out.println("wrote "+new String(b, StandardCharsets.US_ASCII));
byte b1 = b[0];
System.arraycopy(b, 1, b, 0, b.length-1);
b[b.length-1] = b1;
mapped.force();
);
thread2.setDaemon(true);
thread2.start();
LockSupport.parkNanos(TimeUnit.SECONDS.toNanos(5));
thread2.interrupt();
LockSupport.parkNanos(TimeUnit.SECONDS.toNanos(2));
running = false;
Esto demuestra cómo los subprocesos pueden leer y escribir sus datos después de que el canal se ha cerrado y la interrupción del subproceso de escritura no detiene el subproceso de lectura.
Si necesitas realizar FileChannel
operaciones además de las E / S mapeadas en memoria, no hay problema en el uso de múltiples FileChannel
instancias, por lo que cerrar un canal no afecta al otro. P.ej
static volatile boolean running = true;
public static void main(String[] args) throws IOException
Path name = Paths.get("delete.me");
try(FileChannel fc1 = FileChannel.open(name,READ,WRITE,CREATE_NEW,DELETE_ON_CLOSE);
FileChannel fc2 = FileChannel.open(name,READ,WRITE))
Thread thread1 = new Thread(() ->
LockSupport.parkNanos(TimeUnit.MILLISECONDS.toNanos(50));
try
MappedByteBuffer mapped = fc1.map(FileChannel.MapMode.READ_WRITE, 0, 4096);
while(running && !Thread.interrupted())
LockSupport.parkNanos(TimeUnit.MILLISECONDS.toNanos(100));
byte[] b = new byte[5];
mapped.position(4000);
mapped.get(b);
System.out.println("read from map "
+new String(b, StandardCharsets.US_ASCII)
+", file size "+fc1.size());
catch(IOException ex)
ex.printStackTrace();
);
thread1.setDaemon(true);
thread1.start();
Thread thread2 = new Thread(() ->
byte[] b = "HELLO".getBytes(StandardCharsets.US_ASCII);
try
MappedByteBuffer mapped = fc2.map(FileChannel.MapMode.READ_WRITE, 0, 4096);
fc2.position(4096);
try
while(running && !Thread.interrupted())
LockSupport.parkNanos(TimeUnit.MILLISECONDS.toNanos(100));
mapped.position(4000);
mapped.put(b);
System.out.println("wrote to mapped "
+new String(b, StandardCharsets.US_ASCII));
byte b1 = b[0];
System.arraycopy(b, 1, b, 0, b.length-1);
b[b.length-1] = b1;
fc2.write(ByteBuffer.wrap(b));
finally mapped.force();
catch(IOException ex)
ex.printStackTrace();
);
thread2.setDaemon(true);
thread2.start();
LockSupport.parkNanos(TimeUnit.SECONDS.toNanos(5));
thread2.interrupt();
LockSupport.parkNanos(TimeUnit.SECONDS.toNanos(2));
running = false;
Aquí, la interrupción de un hilo cierra su canal, pero no afecta al otro. Además, incluso cuando cada hilo adquiere su propio MappedByteBuffer
desde su propio canal, los cambios se transmiten al otro, incluso sin el uso de force()
. Por supuesto, este último se define como un comportamiento dependiente del sistema, que no se garantiza que funcione en todos los sistemas.
Pero como se muestra con el primer ejemplo, aún puede crear búferes compartidos desde solo uno de los canales al principio, mientras realiza las operaciones de E / S en un canal diferente, uno por hilo, y no importa si y qué canales se cierra, los búferes mapeados no se ven afectados por él.
Puede utilizar la reflexión para acceder a la interruptor
campo ilegalmente y consigue el sun.nio.ch.Interruptible
tipo de clase desde allí para crear una instancia de proxy:
private void doNotCloseOnInterrupt(FileChannel fc)
try
Field field = AbstractInterruptibleChannel.class.getDeclaredField("interruptor");
Class> interruptibleClass = field.getType();
field.setAccessible(true);
field.set(fc, Proxy.newProxyInstance(
interruptibleClass.getClassLoader(),
new Class[] interruptibleClass ,
new InterruptibleInvocationHandler()));
catch (final Exception e)
Jvm.warn().on(getClass(), "Couldn't disable close on interrupt", e);
public class InterruptibleInvocationHandler implements InvocationHandler
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable
// TODO: Check method and handle accordingly
return null;
En Java9 esto funciona con una sola advertencia, ya que se ejecuta de forma predeterminada con --illegal-access=permit
.
Sin embargo, esta bandera podría eliminarse en versiones futuras y la mejor manera de garantizar que esto funcione a largo plazo es usar la bandera --add-opens
:
--add-opens java.base/sun.nio.ch=your-module
--add-opens java.base/java.nio.channels.spi=your-module
O, si no está trabajando con módulos (no recomendado):
--add-opens java.base/sun.nio.ch=ALL-UNNAMED
--add-opens java.base/java.nio.channels.spi=ALL-UNNAMED
Esto funciona con Java 9, Java 10 y la actual compilación de acceso anticipado JDK 11 (28 (2018/8/23)).
Al usar un AsynchronousFileChannel, la excepción ClosedByInterruptException nunca se lanza Simplemente no parece preocuparse por la interrupción
Prueba realizada con jdk 1.8.0_72
import java.io.File;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.channels.AsynchronousFileChannel;
import java.nio.channels.CompletionHandler;
import java.nio.file.Path;
import java.nio.file.StandardOpenOption;
import java.util.concurrent.atomic.AtomicLong;
public class A
static volatile boolean running = true;
public static void main(String[] args) throws IOException, InterruptedException
String name = "delete.me";
Path path = new File(name).toPath();
AtomicLong position = new AtomicLong(0);
AsynchronousFileChannel fc = AsynchronousFileChannel.open(path,
StandardOpenOption.CREATE_NEW, StandardOpenOption.DELETE_ON_CLOSE ,
StandardOpenOption.READ, StandardOpenOption.WRITE,
StandardOpenOption.WRITE, StandardOpenOption.SYNC);
CompletionHandler handler =
new CompletionHandler()
@Override
public void completed(Integer result, Object attachment)
//System.out.println(attachment + " completed with " + result + " bytes written");
position.getAndAdd(result);
@Override
public void failed(Throwable e, Object attachment)
System.err.println(attachment + " failed with:");
e.printStackTrace();
;
Runnable monitorRun = () ->
try
while (running)
System.out.println(name + " is " + (fc.size() >> 10) + " KB");
try
Thread.sleep(1000);
catch (InterruptedException e)
System.out.println("Interrupted");
Thread.currentThread().interrupt();
System.out.println("Interrupt call failed so return");
return;
catch (IOException e)
System.err.println("Monitor thread died");
e.printStackTrace();
;
Thread monitor = new Thread(monitorRun);
monitor.setDaemon(true);
monitor.start();
Thread writer = new Thread(() ->
ByteBuffer bb = ByteBuffer.allocateDirect(32);
try
while (running)
bb.position(0).limit(32);
fc.write(bb,position.get(),null,handler);
try
Thread.sleep(10);
catch (InterruptedException e)
System.out.println("Interrupted");
Thread.currentThread().interrupt();
catch (Exception e)
System.err.println("Writer thread died");
e.printStackTrace();
);
writer.setDaemon(true);
writer.start();
Thread.sleep(5000);
monitor.interrupt();
Thread.sleep(2000);
monitor = new Thread(monitorRun);
monitor.start();
Thread.sleep(5000);
running = false;
fc.close();
Genere la siguiente salida:
delete.me is 0 KB
delete.me is 3 KB
delete.me is 6 KB
delete.me is 9 KB
delete.me is 12 KB
Interrupted
Interrupt call failed so return
delete.me is 21 KB
delete.me is 24 KB
delete.me is 27 KB
delete.me is 30 KB
delete.me is 33 KB
Nos puedes añadir valor a nuestra información cooperando tu experiencia en los informes.