重发数据包优先

This commit is contained in:
Administrator
2023-01-05 08:19:54 +08:00
parent 62b22410a3
commit ea97e3891f
11 changed files with 428 additions and 42 deletions
+4
View File
@@ -1 +1,5 @@
/bin/ /bin/
/frpc/
/klalbs4.json
/klalbs.json
/klalbs2.json
+1 -2
View File
@@ -1,9 +1,8 @@
package org.kne.cloud.network.klalb; package org.kne.cloud.network.klalb;
public class Consts { public class Consts {
public static final int BLOCKSIZE=16384; public static final int BLOCKSIZE=8192;
public static final long PINGTIMENS=1000000000L; public static final long PINGTIMENS=1000000000L;
public static final double A = 0.125;
public static final int SO_TIMEOUT = 20000; public static final int SO_TIMEOUT = 20000;
public static final long SN_KEEP = 60000000000L; public static final long SN_KEEP = 60000000000L;
public static final int MAX_RESEND = 100; public static final int MAX_RESEND = 100;
@@ -24,6 +24,8 @@ public class KLALBBlock implements Comparable<KLALBBlock>{
public transient volatile long sendtime; public transient volatile long sendtime;
public transient volatile int resend; public transient volatile int resend;
public long sendtimeForRTT;
public KLALBBlock() { public KLALBBlock() {
sn=sng.getAndIncrement(); sn=sng.getAndIncrement();
@@ -67,6 +67,7 @@ public class KLALBClient {
public void listenProxy() { public void listenProxy() {
for (int i = 0; i < pet.size(); i++) { for (int i = 0; i < pet.size(); i++) {
ProxyElement pe=pet.get(i); ProxyElement pe=pet.get(i);
if(pe.getIpport().getPort()>0&&pe.getIpport().getPort()<65536)
try { try {
open(pe); open(pe);
} catch (IOException e) { } catch (IOException e) {
+123 -30
View File
@@ -32,10 +32,15 @@ import java.util.concurrent.Executors;
import java.util.concurrent.LinkedBlockingQueue; import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.atomic.AtomicInteger; import java.util.concurrent.atomic.AtomicInteger;
import java.util.function.Predicate; import java.util.function.Predicate;
import java.util.zip.DataFormatException;
import org.kne.cloud.network.mport.ThreadTool; import org.kne.cloud.network.mport.ThreadTool;
public class KLALBCore { public class KLALBCore {
private volatile long RTT=1000000000;
private volatile long RTO=1000000000;
private volatile long DevRTT=0;
private volatile int cacheblocks; private volatile int cacheblocks;
private Map<Integer, LocalTCPConnection> localtcps = new ConcurrentHashMap<>(); private Map<Integer, LocalTCPConnection> localtcps = new ConcurrentHashMap<>();
@@ -104,7 +109,7 @@ public class KLALBCore {
pdb.pingtime=System.nanoTime(); pdb.pingtime=System.nanoTime();
tc.sendBlock(pdb); tc.sendBlock(pdb);
} }
if(!tc.getNDSendDeque().isEmpty()||!tc.getSendDeque().isEmpty()) if(!tc.getNDSendDeque().isEmpty()||!tc.getSendDeque().isEmpty()||!tc.getReSendDeque().isEmpty())
break; break;
synchronized (tc.getSendDeque()) { synchronized (tc.getSendDeque()) {
tc.getSendDeque().wait(10); tc.getSendDeque().wait(10);
@@ -112,19 +117,32 @@ public class KLALBCore {
} }
KLALBBlock k0=tc.getNDSendDeque().poll(); KLALBBlock k0=tc.getNDSendDeque().poll();
if(k0!=null) { if(k0!=null) {
tc.sendBlock(k0,tc.getNDSendDeque().isEmpty()); if(k0.cuid==0&&k0.number==0&&k0.command==1) {
k0.pingtime+=System.nanoTime()- k0.sendtime;
}
tc.sendBlock(k0);
}else {
KLALBBlock k1=tc.getReSendDeque().poll();
if(k1!=null) {
tc.sendBlock(k1);
}else { }else {
KLALBBlock k=tc.getSendDeque().poll(); KLALBBlock k=tc.getSendDeque().poll();
if(k!=null) { if(k!=null) {
//if(localtcps.containsKey(k.cuid)||k.cuid.equals(ZERO_UUID)) //if(localtcps.containsKey(k.cuid)||k.cuid.equals(ZERO_UUID))
tc.sendBlock(k,tc.getSendDeque().isEmpty()); tc.sendBlock(k);
}
} }
} }
} }
public void remoteReceive(RemoteTCPConnection tc) throws IOException { public void remoteReceive(RemoteTCPConnection tc) throws IOException {
KLALBBlock brc=null; KLALBBlock brc=null;
for(;;) { for(;;) {
try {
brc=tc.receiveBlock(); brc=tc.receiveBlock();
} catch (DataFormatException e) {
throw new StreamCorruptedException("ZIP error");
}
brc.sendtime=System.nanoTime();
if(brc.number!=0||brc.sn==0) { if(brc.number!=0||brc.sn==0) {
break; break;
} }
@@ -156,11 +174,26 @@ public class KLALBCore {
pdb.number=0; pdb.number=0;
pdb.command=1; pdb.command=1;
pdb.pingtime=brc.pingtime; pdb.pingtime=brc.pingtime;
pdb.sendtime=brc.sendtime;
tc.getNDSendDeque().offer(pdb); tc.getNDSendDeque().offer(pdb);
}else if(brc.command==1) { }else if(brc.command==1) {
long cur=System.nanoTime(); long cur=System.nanoTime();
long delay=(cur-brc.pingtime)/2; long delay=cur-brc.pingtime;
tc.setDelayAvg(delay); tc.setDelayAvg(delay);
synchronized (remotetcps) {
Collections.sort(remotetcps, new Comparator<RemoteTCPConnection>() {
@Override
public int compare(RemoteTCPConnection o1, RemoteTCPConnection o2) {
if(o1.getDelay()>o2.getDelay()) {
return 1;
}else if(o1.getDelay()<o2.getDelay()){
return -1;
}else {
return 0;
}
}
});
}
} }
} }
}else { }else {
@@ -191,7 +224,7 @@ public class KLALBCore {
ack.cuid=brc.cuid; ack.cuid=brc.cuid;
ack.number=-brc.number; ack.number=-brc.number;
ack.cacheused=ltcs.getSendDeque().size(); ack.cacheused=ltcs.getSendDeque().size();
submitDataBlockNoDelay(ack); submitAckBlockNoDelay(ack,3);
} }
@@ -199,34 +232,60 @@ public class KLALBCore {
long nx=-brc.number; long nx=-brc.number;
LocalTCPConnection ltc=localtcps.get(brc.cuid); LocalTCPConnection ltc=localtcps.get(brc.cuid);
if(ltc!=null) { if(ltc!=null) {
ltc.getOutputcache().removeIf((b) -> { List<KLALBBlock> l=ltc.getOutputcache();
synchronized (l) {
for (Iterator<KLALBBlock> iterator = l.iterator(); iterator.hasNext();) {
KLALBBlock klalbBlock = (KLALBBlock) iterator.next();
if(klalbBlock.number==nx) {
iterator.remove();
long SampleRTT=System.nanoTime()-klalbBlock.sendtimeForRTT;
RTT=(RTT*19+SampleRTT)/20;
DevRTT = (3*DevRTT + Math.abs( SampleRTT - RTT))/4;
RTO=RTT+DevRTT;
//System.out.println(RTO/1000000);
}
}
}
/*ltc.getOutputcache().removeIf((b) -> {
return b.number == nx; return b.number == nx;
}); });*/
ltc.setPeerCacheUsed(brc.cacheused); ltc.setPeerCacheUsed(brc.cacheused);
} }
} }
} }
} }
public void submitDataBlock(KLALBBlock kb) throws InterruptedException { public void submitDataBlock(KLALBBlock ks) throws InterruptedException {
submitDataBlock(ks,1);
}
public void submitDataBlock(KLALBBlock kb,int i) throws InterruptedException {
int ni=Math.min(i, remotetcps.size());
while(true) { while(true) {
synchronized (remotetcps) { synchronized (remotetcps) {
Collections.sort(remotetcps, new Comparator<RemoteTCPConnection>() {
@Override
public int compare(RemoteTCPConnection o1, RemoteTCPConnection o2) {
if(o1.getDelay()>o2.getDelay()) {
return 1;
}else if(o1.getDelay()<o2.getDelay()){
return -1;
}else {
return 0;
}
}
});
//System.out.println(remotetcps);
for (Iterator<RemoteTCPConnection> iterator = remotetcps.iterator(); iterator.hasNext();) { for (Iterator<RemoteTCPConnection> iterator = remotetcps.iterator(); iterator.hasNext();) {
RemoteTCPConnection remoteTCPConnection = (RemoteTCPConnection) iterator.next(); RemoteTCPConnection remoteTCPConnection = (RemoteTCPConnection) iterator.next();
Queue<KLALBBlock> bdq=remoteTCPConnection.getSendDeque(); Queue<KLALBBlock> bdq=remoteTCPConnection.getSendDeque();
if(bdq.size()<1) {
bdq.add(kb);
synchronized (bdq) {
bdq.notifyAll();
}
ni--;
if(ni<=0)
return;
}
}
}
Thread.sleep(1);
}
}
public void submitReDataBlock(KLALBBlock kb) throws InterruptedException {
while(true) {
synchronized (remotetcps) {
for (Iterator<RemoteTCPConnection> iterator = remotetcps.iterator(); iterator.hasNext();) {
RemoteTCPConnection remoteTCPConnection = (RemoteTCPConnection) iterator.next();
Queue<KLALBBlock> bdq=remoteTCPConnection.getReSendDeque();
if(bdq.size()<1) { if(bdq.size()<1) {
bdq.add(kb); bdq.add(kb);
synchronized (bdq) { synchronized (bdq) {
@@ -252,20 +311,54 @@ public class KLALBCore {
} }
} }
} }
public void submitAckBlockNoDelay(KLALBBlock kb,int limit) {
synchronized (remotetcps) {
int coun=0;
for (Iterator<RemoteTCPConnection> iterator = remotetcps.iterator(); iterator.hasNext();) {
if(coun>=limit) {
return;
}
RemoteTCPConnection rmt = (RemoteTCPConnection) iterator.next();
Queue<KLALBBlock> sq = rmt.getNDSendDeque();
sq.offer(kb);
synchronized (sq) {
sq.notifyAll();
}
coun++;
}
}
}
public void putDataBlock(LocalTCPConnection tc, KLALBBlock ks) throws InterruptedException { public void putDataBlock(LocalTCPConnection tc, KLALBBlock ks) throws InterruptedException {
while (!tc.getOutputcache().isEmpty()&&(tc.getOutputcount()-tc.getOutputcache().get(0).number>cacheblocks)) { while (true) {
boolean b;
synchronized (ks) {
b=!tc.getOutputcache().isEmpty()&&(tc.getOutputcount()-tc.getOutputcache().get(0).number>cacheblocks);
}
if(!b) {
break;
}
Thread.sleep(1); Thread.sleep(1);
} }
ks.sendtime=System.nanoTime(); ks.sendtime=System.nanoTime();
tc.getOutputcache().add(ks); ks.sendtimeForRTT=ks.sendtime;
//System.out.println(tc.getOutputcache().size());
if(ks.data==null) {
submitDataBlock(ks); submitDataBlock(ks);
if(tc.getPeerCacheUsed()>cacheblocks) { }else {
if(ks.data.length<Consts.BLOCKSIZE/2) {
submitDataBlock(ks,2);
}else {
submitDataBlock(ks);
}
}
tc.getOutputcache().add(ks);
int peerCacheUsed = tc.getPeerCacheUsed();
if(peerCacheUsed>cacheblocks) {
while( tc.getPeerCacheUsed()>cacheblocks) { while( tc.getPeerCacheUsed()>cacheblocks) {
Thread.sleep(1); Thread.sleep(1);
} }
}else if(tc.getPeerCacheUsed()>cacheblocks/2){ }else if(peerCacheUsed>cacheblocks/2){
Thread.sleep(tc.getPeerCacheUsed()-cacheblocks/2); Thread.sleep(peerCacheUsed-cacheblocks/2);
} }
} }
@@ -276,15 +369,15 @@ public class KLALBCore {
for (int i = 0; i < l.size(); i++) { for (int i = 0; i < l.size(); i++) {
KLALBBlock block=l.get(i); KLALBBlock block=l.get(i);
long timex = (System.nanoTime() - block.sendtime) / 1000000; long timex = (System.nanoTime() - block.sendtime) / 1000000;
if (timex > 200*(1<<Math.min(8,block.resend))+1000*i) { if ((i==0&&timex>100)||timex > (RTO/1000000)*(1<<Math.min(8,block.resend))+2000*i) {
submitDataBlock(block); submitReDataBlock(block);
block.sendtime = System.nanoTime(); block.sendtime = System.nanoTime();
block.resend++; block.resend++;
if(block.resend>=Consts.MAX_RESEND) { if(block.resend>=Consts.MAX_RESEND) {
l.remove(i); l.remove(i);
i--; i--;
} }
System.out.println("超时重传:"+block); System.out.println("超时重传:"+block+" 位置:"+i);
} }
} }
} }
@@ -10,6 +10,7 @@ import java.io.OutputStream;
import java.io.StreamCorruptedException; import java.io.StreamCorruptedException;
import java.net.Socket; import java.net.Socket;
import java.net.UnknownHostException; import java.net.UnknownHostException;
import java.util.Arrays;
import java.util.Queue; import java.util.Queue;
import java.util.Random; import java.util.Random;
import java.util.UUID; import java.util.UUID;
@@ -18,8 +19,11 @@ import java.util.concurrent.BlockingDeque;
import java.util.concurrent.BlockingQueue; import java.util.concurrent.BlockingQueue;
import java.util.concurrent.ConcurrentLinkedQueue; import java.util.concurrent.ConcurrentLinkedQueue;
import java.util.concurrent.LinkedBlockingDeque; import java.util.concurrent.LinkedBlockingDeque;
import java.util.zip.DataFormatException;
import java.util.zip.Deflater;
import java.util.zip.GZIPInputStream; import java.util.zip.GZIPInputStream;
import java.util.zip.GZIPOutputStream; import java.util.zip.GZIPOutputStream;
import java.util.zip.Inflater;
import org.kne.cloud.network.mport.IPPort; import org.kne.cloud.network.mport.IPPort;
import org.kne.io.AddInputStream; import org.kne.io.AddInputStream;
@@ -40,6 +44,8 @@ public class RemoteTCPConnection extends TCPConnection {
} }
protected void initIOs() throws IOException { protected void initIOs() throws IOException {
connect.setTrafficClass(0x10);
connect.setTcpNoDelay(true);
OutputStream outm=null; OutputStream outm=null;
InputStream inm=null; InputStream inm=null;
if(tunnel!=null) { if(tunnel!=null) {
@@ -58,8 +64,8 @@ public class RemoteTCPConnection extends TCPConnection {
} }
dout = new DataOutputStream(new BufferedOutputStream(outm,Consts.BLOCKSIZE*2+1) ); dout = new DataOutputStream(outm);
din = new DataInputStream(new BufferedInputStream(inm,Consts.BLOCKSIZE*2+1)); din = new DataInputStream(inm);
} }
@Override @Override
@@ -133,8 +139,17 @@ public class RemoteTCPConnection extends TCPConnection {
if (data.data == null) { if (data.data == null) {
dout.writeShort(-1); dout.writeShort(-1);
} else { } else {
dout.writeShort(data.data.length); Deflater def = new Deflater(Deflater.BEST_COMPRESSION, true);
dout.write(data.data); def.setInput(data.data);
def.finish();
byte[] b = new byte[(int)(data.data.length * 1.1D) + 64];
int nsize = def.deflate(b);
def.end();
this.dout.writeShort(nsize);
this.dout.write(b, 0, nsize);
/*dout.writeShort(data.data.length);
dout.write(data.data);*/
//System.out.println(Arrays.toString(data.data));
} }
} else if (data.number == 0) { } else if (data.number == 0) {
dout.write(data.command); dout.write(data.command);
@@ -165,7 +180,7 @@ public class RemoteTCPConnection extends TCPConnection {
//System.out.println("SEND:" + data); //System.out.println("SEND:" + data);
} }
public KLALBBlock receiveBlock() throws IOException { public KLALBBlock receiveBlock() throws IOException, DataFormatException {
KLALBBlock klb = new KLALBBlock(); KLALBBlock klb = new KLALBBlock();
klb.cuid = din.readInt(); klb.cuid = din.readInt();
klb.number = din.readLong(); klb.number = din.readLong();
@@ -176,7 +191,18 @@ public class RemoteTCPConnection extends TCPConnection {
} else { } else {
byte[] d = new byte[size]; byte[] d = new byte[size];
din.readFully(d); din.readFully(d);
klb.data = d; Inflater in = new Inflater(true);
in.setInput(d);
byte[] b = new byte[8192];
int nsize = in.inflate(b);
in.end();
if (nsize == b.length) {
klb.data = b;
} else {
klb.data = Arrays.copyOf(b, nsize);
}
//System.out.println(Arrays.toString(d));
//klb.data = d;
} }
} else if (klb.number == 0) { } else if (klb.number == 0) {
klb.command = din.read(); klb.command = din.read();
@@ -222,7 +248,11 @@ public class RemoteTCPConnection extends TCPConnection {
public Queue<KLALBBlock> getNDSendDeque() { public Queue<KLALBBlock> getNDSendDeque() {
return NDsendDeque; return NDsendDeque;
} }
private Queue<KLALBBlock> resendDeque = new ConcurrentLinkedQueue<>();
public Queue<KLALBBlock> getReSendDeque() {
return sendDeque;
}
private Queue<KLALBBlock> sendDeque = new ConcurrentLinkedQueue<>(); private Queue<KLALBBlock> sendDeque = new ConcurrentLinkedQueue<>();
public Queue<KLALBBlock> getSendDeque() { public Queue<KLALBBlock> getSendDeque() {
+1 -1
View File
@@ -138,7 +138,7 @@ public class Tunnel{
try { try {
p = Runtime.getRuntime().exec("./frpc/frpc_windows_386.exe",null,f); p = Runtime.getRuntime().exec("./frpc/frpc_windows_amd64.exe",null,f);
BufferedReader brd=new BufferedReader(new InputStreamReader( p.getInputStream())); BufferedReader brd=new BufferedReader(new InputStreamReader( p.getInputStream()));
+25
View File
@@ -0,0 +1,25 @@
package org.kne.debug;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Hashtable;
import java.util.List;
import java.util.Map;
public class TimeDebugger {
Map<String,Long> l=new Hashtable<String,Long>();
long tmp=-1;
public void putTime(String name){
long v=System.currentTimeMillis();
if(tmp==-1){
l.put(name, 0l);
}else{
l.put(name, v-tmp);
}
tmp=v;
}
public void print(){
System.err.println(l+"(ms)");
}
}
+188
View File
@@ -0,0 +1,188 @@
package org.kne.io;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.EOFException;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.concurrent.Executors;
import java.util.concurrent.ThreadFactory;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.zip.DataFormatException;
import java.util.zip.Deflater;
import java.util.zip.Inflater;
import org.kne.debug.TimeDebugger;
public class Compress {
static int n=0;
public static ThreadPoolExecutor exf=(ThreadPoolExecutor) Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors()*2, new ThreadFactory() {
@Override
public Thread newThread(Runnable r) {
Thread t=new Thread(r,"Compress #"+(n++));
t.setDaemon(true);
return t;
}
});
public static Data compress(Data b) {
Deflater def=new Deflater(Deflater.BEST_COMPRESSION, true);
def.setInput(b.b,b.off,b.len);
def.finish();
byte[]bo=new byte[(int) (b.len*1.1)+64];
int vp=def.deflate(bo,4,bo.length-4);
def.end();
int v=b.len;
bo[0]=(byte) ((v >>> 24) & 0xFF);
bo[1]=(byte) ((v >>> 16) & 0xFF);
bo[2]=(byte) ((v >>> 8) & 0xFF);
bo[3]=(byte) ((v >>> 0) & 0xFF);
return new Data(bo,0,vp+4);
}
public static Data uncompress(Data b) throws IOException, DataFormatException {
if(b.len<4){
throw new EOFException("!!");
}
int ch1 =b.b[b.off+0]&0xff;
int ch2 = b.b[b.off+1]&0xff;
int ch3 =b. b[b.off+2]&0xff;
int ch4 =b.b[b.off+3]&0xff;
int zix= ((ch1 << 24) + (ch2 << 16) + (ch3 << 8) + (ch4 << 0));
Inflater inf=new Inflater(true);
inf.setInput(b.b, b.off+4, b.len-4);
byte[]d=new byte[zix];
int l=inf.inflate(d);
inf.end();
return new Data(d,0,l);
}
private static class compresstask extends Task{
volatile Data input,output;
public compresstask(Data input) {
super();
this.input = input;
}
public Data getOutput() {
return output;
}
@Override
protected void runTask() {
output=compress(input);
}
}
public static void mulcomp(DataOutputStream dos,byte[]in, TimeDebugger dbg) throws IOException {
ArrayList<Task> l=new ArrayList();
int count =4;
int sze=in.length/count;
int y=in.length%count;
for (int i = 0; i < count; i++) {
Task t=new compresstask(new Data(in,i*sze,sze));
exf.execute(t);
l.add(t);
}
Data tmp=null;
if(y>0) {
tmp=compress(new Data(in,count*sze,y));
}
dbg.putTime("compress");
dos.writeInt(l.size()+(tmp==null?0:1));
for (int i = 0; i < l.size(); i++) {
compresstask n=(compresstask) l.get(i);
n.waitfortask();
Data g=n.getOutput();
dos.writeInt(g.len);
dos.write(g.b, g.off, g.len);
}
if(tmp!=null) {
dos.writeInt(tmp.len);
dos.write(tmp.b, tmp.off, tmp.len);
}
}
private static class uncompresstask extends Task{
volatile Data input,output;
public uncompresstask(Data input) {
super();
this.input = input;
}
public Data getOutput() {
return output;
}
@Override
protected void runTask() {
try {
output=uncompress(input);
} catch (IOException e) {
// TODO Զɵ catch
e.printStackTrace();
} catch (DataFormatException e) {
// TODO Զɵ catch
e.printStackTrace();
}
}
}
public static byte[] muluncomp(DataInputStream dis,TimeDebugger dbg) throws IOException, DataFormatException {
ArrayList<Task> l=new ArrayList();
ByteArrayOutputStream bod=new ByteArrayOutputStream(1024);
int bc=dis.readInt();
for(int x=0;x<bc;x++) {
int s=dis.readInt();
byte []input=new byte[s];
int offset = 0;
int numRead = 0;
while (offset < input.length
&& (numRead = dis.read(input, offset, input.length - offset)) >= 0) {
offset += numRead;
}
Task tsk=new uncompresstask(new Data(input,0,input.length));
exf.execute(tsk);
l.add(tsk);
//Data rez=uncompress(new Data(input,0,input.length));
} dbg.putTime("read");
for (int i = 0; i < l.size(); i++) {
uncompresstask uct=(uncompresstask) l.get(i);
uct.waitfortask();
Data rez=uct.getOutput();
bod.write(rez.b,rez.off,rez.len);
}
//rez.b.length=rez.off;
return bod.toByteArray();
}
public static void main(String[] args) throws IOException, DataFormatException {
String s="jjjjjjjjjjjjjjjjjjhjhjhm";
byte[] ib=s.getBytes();
Data i=new Data(ib,0,ib.length);
Data o=compress(i);
Data d=uncompress(o);
System.out.println(o.len+" "+d.len);
//for (int j = d.off; j < d.off+d.len; j++) {
System.out.println(new String(d.b,d.off,d.len));
//}
}
}
+13
View File
@@ -0,0 +1,13 @@
package org.kne.io;
public class Data {
byte[]b;
int off,len;
public Data(byte[] b, int off, int len) {
super();
this.b = b;
this.off = off;
this.len = len;
}
}
+31
View File
@@ -0,0 +1,31 @@
package org.kne.io;
public abstract class Task implements Runnable{
private volatile boolean begin=false,end=false;
private volatile Object t=new Object();
@Override
public void run() {
begin=true;
runTask();
end=true;
if(t!=null) {
synchronized(t) {
t.notifyAll();
}
}
}
public void waitfortask() {
synchronized(t){
try {
while(!end) {
t.wait(1);
}
} catch (InterruptedException e) {
e.printStackTrace();
}}
}
protected abstract void runTask();
}