Multithread in aspose-slides-20.4 for java

Hi, I am using aspose-slides-20.4 for java to convert PPT to PDF using method save(). As to providing support to interrupt, I set InterruptionTokenSource in its LoadOptions.

My code is like this:
monitor = new com.aspose.slides.InterruptionTokenSource();
com.aspose.slides.LoadOptions loadOptions = new com.aspose.slides.LoadOptions();
loadOptions.setInterruptionToken(monitor.getToken());
presentation = new com.aspose.slides.Presentation(sourceFilePath, loadOptions);
presentation.save(targetFilePath, com.aspose.slides.SaveFormat.Pdf, slideToPdfOptions);

It works well in sigle thread mode, but if i want to convert different PPT in the same time with Multithread, it got troubled. Only one thread work while others are blocked.

“converter-5@14261” prio=5 tid=0x9e nid=NA runnable
java.lang.Thread.State: RUNNABLE
blocks converter-4@11319
blocks converter-2@11309
blocks converter-3@11307
blocks converter-1@11304
at java.nio.IntBuffer.get(IntBuffer.java:691)
at java.nio.IntBuffer.get(IntBuffer.java:715)
at com.aspose.slides.internal.fc.do.do(Unknown Source:-1)
at com.aspose.slides.internal.fc.do.do(Unknown Source:-1)
at com.aspose.slides.internal.be.do.do(Unknown Source:-1)
at com.aspose.slides.internal.bg.if.do(Unknown Source:-1)
at com.aspose.slides.internal.bf.for.new(Unknown Source:-1)
at com.aspose.slides.internal.bf.do$1.do(Unknown Source:-1)
at com.aspose.slides.internal.bg.char.do(Unknown Source:-1)
at com.aspose.slides.internal.bg.char.for(Unknown Source:-1)
at com.aspose.slides.internal.be.do.int(Unknown Source:-1)
at com.aspose.slides.internal.bd.int.new(Unknown Source:-1)
at com.aspose.slides.internal.bd.int.do(Unknown Source:-1)
at com.aspose.slides.internal.cr.if.do(Unknown Source:-1)
at com.aspose.slides.internal.cr.for.do(Unknown Source:-1)
at com.aspose.slides.internal.mz.import.do(Unknown Source:-1)
at com.aspose.slides.ac5.do(Unknown Source:-1)
- locked <0x44c2> (a java.lang.Object)
at com.aspose.slides.Picture.do(Unknown Source:-1)
at com.aspose.slides.m8.do(Unknown Source:-1)
at com.aspose.slides.m8.do(Unknown Source:-1)
at com.aspose.slides.m8.do(Unknown Source:-1)
at com.aspose.slides.m8.(Unknown Source:-1)
at com.aspose.slides.OleObjectFrame.do(Unknown Source:-1)
at com.aspose.slides.GroupShape.do(Unknown Source:-1)
at com.aspose.slides.Slide.for(Unknown Source:-1)
at com.aspose.slides.Slide.do(Unknown Source:-1)
at com.aspose.slides.Slide.do(Unknown Source:-1)
at com.aspose.slides.Slide.do(Unknown Source:-1)
at com.aspose.slides.afm.do(Unknown Source:-1)
at com.aspose.slides.afm.do(Unknown Source:-1)
at com.aspose.slides.Presentation.do(Unknown Source:-1)
at com.aspose.slides.Presentation.save(Unknown Source:-1)
at com.converter.converter.impl.SlideConverter.convert(SlideConverter.java:35)
at com.converter.core.ConvertRunnable.proceed(ConvertRunnable.java:72)
at com.converter.core.ConvertRunnable.run(ConvertRunnable.java:44)
at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:511)
at java.util.concurrent.FutureTask.run$$$capture(FutureTask.java:266)
at java.util.concurrent.FutureTask.run(FutureTask.java:-1)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
at java.lang.Thread.run(Thread.java:748)

As you can see, the first thread lock an object which other threads waiting for. When I look into souce code, I found there is a synchronized job in it

The method is in “com.aspose.slides.ac5”, with function "final byte do(w9 var1, strictfp var2, ahr var3, IBaseSlide var4, nb var5, boolean var6) " And there is the code

final byte do(w9 paramw9, strictfp paramstrictfp, ahr paramahr, IBaseSlide paramIBaseSlide, nb paramnb, boolean paramBoolean) {
byte byte = paramw9.for();
case case1 = case.do(this.for.byte());
String str = t.do("{0}:{1}", new Object[] { this.for.long().toString(), this.new.do(paramIBaseSlide, paramnb) });
if (!do(this.new))
case1 = case.do(case1, (int)new try(str));
byte byte1 = ahr.do(paramahr, case1, this.for);
if (paramahr == null || r.if(paramahr.try()) || (paramahr.int() && import.for(byte1.if())))
return do(paramahr, byte1, paramIBaseSlide, paramnb);
double d1 = 0.0D;
double d2 = 0.0D;
double[] arrayOfDouble1 = { d1 };
double[] arrayOfDouble2 = { d2 };
do(byte1.if(), paramahr.try(), paramstrictfp.new(), byte, arrayOfDouble1, arrayOfDouble2);
d1 = arrayOfDouble1[0];
d2 = arrayOfDouble2[0];
if (paramw9.do() != null && paramw9.do().while().final().do()[0] != 0.0F && paramw9.do().while().final().do()[3] != 0.0F && d1 > 1.0D && d2 > 1.0D) {
d1 /= ai.do(paramw9.do().while().final().do()[0]);
d2 /= ai.do(paramw9.do().while().final().do()[3]);
if (for.if(paramw9.do(), protected.class) && !import.int(byte1.if())) {
char c = ';
if (byte1.if().case() > c)
d1 /= ai.int((byte1.if().case() / c));
if (byte1.if().break() > c)
d2 /= ai.int((byte1.if().break() / c));
}
}
if (ai.do(d1 - 1.0D) < 0.05D && ai.do(d2 - 1.0D) < 0.05D) {
byte byte3 = null;
byte[] arrayOfByte1 = { byte3 };
boolean bool1 = !paramahr.goto().do(case1, (Object[])arrayOfByte1) ? true : false;
byte3 = arrayOfByte1[0];
if (bool1)
byte3 = do(paramahr, byte1, paramIBaseSlide, paramnb);
if (import.int(byte1.if()) && (paramBoolean || paramstrictfp.if() > byte1.if().catch() || paramstrictfp.for() > byte1.if().byte())) {
for for = new for(paramstrictfp.if(), paramstrictfp.for());
case case = case.do(case1, (int)for);
byte byte4 = null;
byte[] arrayOfByte2 = { byte4 };
boolean bool2 = !paramahr.goto().do(case, (Object[])arrayOfByte2) ? true : false;
byte4 = arrayOfByte2[0];
if (bool2) {
class class;
strictfp strictfp1 = new strictfp(paramstrictfp.if() * 4.0F, paramstrictfp.for() * 4.0F);
if if = import.do(byte1.int(), new extends(new static(0.0F, 0.0F), strictfp1.new()));
if (!do(this.new))
class = this.new.do(paramIBaseSlide, paramnb, if);
byte4 = new byte(class);
paramahr.goto().do(case, byte4);
}
return byte4;
}
return byte3;
}
new new = new new((int)new try(str), d1, d2);
case case2 = case.do(case1, (int)new);
byte byte2 = null;
byte[] arrayOfByte = { byte2 };
boolean bool = !paramahr.goto().do(case2, (Object[])arrayOfByte) ? true : false;
byte2 = arrayOfByte[0];
if (bool) {
continue continue = new continue(for.int(Double.valueOf(ai.int((byte1.if().catch() / (float)d1))), 14), for.int(Double.valueOf(ai.int((byte1.if().byte() / (float)d2))), 14));
byte byte3 = do(paramahr, byte1, paramIBaseSlide, paramnb, continue.int());
class class = byte3.if();
if (class.void().equals(continue.int()))
return byte3;
if (import.int(byte3.if())) {
byte[] arrayOfByte2;
case case = null;
continue continue1 = case.do().int();
int i = continue1.if();
int j = continue1.for();
byte[] arrayOfByte1 = getImage().getBinaryData();
int int = new int(arrayOfByte1);
if (“image/x-wmf”.equals(getImage().getContentType()) && int.void().if() > i && int.long().goto() == 0.0F && int.long().long() == 0.0F)
case = new case(0.0D, 1.0D - i / class.catch(), 0.0D, (j / class.byte() > 1.0D) ? 0.0D : (1.0D - j / class.byte()));
boolean bool1 = (int.break() == 5 && int.long().else() != int.void().if() && int.long().goto() > 0.0F && int.long().long() > 0.0F && int.long().else() < 2000.0F) ? true : false;
if (paramw9.do() != null && paramw9.do().while().final().do()[0] != 0.0F && paramw9.do().while().final().do()[3] != 0.0F && bool1) {
continue = new continue(for.int(Float.valueOf(paramstrictfp.if() * ai.do(paramw9.do().while().final().do()[0])), 13), for.int(Float.valueOf(paramstrictfp.for() * ai.do(paramw9.do().while().final().do()[3])), 13));
} else if (!bool1) {
continue = new continue(for.int(Float.valueOf(paramstrictfp.if() * 4.0F), 13), for.int(Float.valueOf(paramstrictfp.for() * 4.0F), 13));
}
synchronized (char) {
** arrayOfByte2 = import.if((class)import.do(arrayOfByte1, new extends(0.0F, 0.0F, continue.if(), continue.for())));**
** }**
byte2 = new byte(import.try(arrayOfByte2), arrayOfByte2);
case case3 = case.do(byte2.int());
paramahr.goto().do(case3, byte2);
} else {
if if = new if(class, continue.int());
try {
byte[] arrayOfByte1 = import.if((class)if);
byte2 = new byte(import.try(arrayOfByte1), arrayOfByte1);
case case = case.do(byte2.int());
paramahr.goto().do(case, byte2);
} finally {
if (if != null)
if.dispose();
}
}
}
return byte2;
}

The main reason is
synchronized (char) {
arrayOfByte2 = import.if((class)import.do(arrayOfByte1, new extends(0.0F, 0.0F, continue.if(), continue.for())));
}
while “char” is actually an java Object.

By the way, if the thread are blocked to wait for the lock, I can’t interrupt it, what can I do to solve the problem?
Thanks.

@Evan347,

I have observed your requiremetns and like to share that Aspose.Slides does not have any issue while using in multi-threaded environment. If one thread is blocked unless previously running thread does not complete may be related to some implementation limitation on your end. Can you please provide a sample project that is reproducing the issue along with snapshot of issue incurring.

Thank you for your reply. Actually I just use save() method to convert, then submit to the threadpool, I don’t think it’s my code limitation. When I trace the code, I found it was blocked just before using com.aspose.slides.internal.*, before that, it was dealing with com.aspose.slides.Picture. I will show you the defference between the nomal one and the blocked one:

nomal:
“converter-5@14261” prio=5 tid=0x9e nid=NA runnable
java.lang.Thread.State: RUNNABLE
blocks converter-4@11319
blocks converter-2@11309
blocks converter-3@11307
blocks converter-1@11304

at com.aspose.slides.internal.cr.if.do(Unknown Source:-1)
at com.aspose.slides.internal.cr.for.do(Unknown Source:-1)
at com.aspose.slides.internal.mz.import.do(Unknown Source:-1)
at com.aspose.slides.ac5.do(Unknown Source:-1)
- locked <0x44c2> (a java.lang.Object)
at com.aspose.slides.Picture.do(Unknown Source:-1)
at com.aspose.slides.m8.do(Unknown Source:-1)
at com.aspose.slides.m8.do(Unknown Source:-1)
at com.aspose.slides.m8.do(Unknown Source:-1)
at com.aspose.slides.m8.(Unknown Source:-1)
at com.aspose.slides.OleObjectFrame.do(Unknown Source:-1)
at com.aspose.slides.GroupShape.do(Unknown Source:-1)

blocked:
waiting for converter-5@14261 to release lock on <0x44c2> (a java.lang.Object)
at com.aspose.slides.ac5.do(Unknown Source:-1)
at com.aspose.slides.Picture.do(Unknown Source:-1)
at com.aspose.slides.m8.do(Unknown Source:-1)
at com.aspose.slides.m8.do(Unknown Source:-1)
at com.aspose.slides.m8.do(Unknown Source:-1)
at com.aspose.slides.m8.(Unknown Source:-1)
at com.aspose.slides.OleObjectFrame.do(Unknown Source:-1)
at com.aspose.slides.GroupShape.do(Unknown Source:-1)

As you can see, the blocked one just wait for the lock which locked by the nomal one. When I decompiled the code, I found that there is a synchronized job in it
synchronized (char) {
** arrayOfByte2 = import.if((class)import.do(arrayOfByte1, new extends(0.0F, 0.0F, continue.if(), continue.for())));**
** }**
while char below is actually an Object, import.do is what we need to do to enter into com.aspose.slides.internal.*. However, it’s synchronous. I don’t know why the synchronous job could affect the other job in another thread, could you help?
Thanks.

https://send.firefox.com/download/72e541c011a848ba/#nttcv8sC5xDRbZ1zrolnMg

I just made a demo for it. You can see thread 2 and thread 5 are blocked for a long time at the same place.

@Evan347,

Thank you for sharing the detailed information. An issue with ID SLIDESJAVA-38102 has been created as investigation in our issue queue to further investigate and resolve the issue. This thread has been linked with the issue so that you may be notified once the issue will be fixed.