Java 为客户端发送的每个文件创建新线程(套接字)

Java 为客户端发送的每个文件创建新线程(套接字),java,multithreading,sockets,concurrency,semaphore,Java,Multithreading,Sockets,Concurrency,Semaphore,我正在使用套接字开发应用程序。客户端正在监视特定目录,当用户在其中添加文件时,客户端通过套接字将该文件发送到服务器端的特定目录。 现在我已经实现了信号量,使许多文件同时发送到服务器。 这就是我的问题开始的地方。我正在使用while循环,当客户端试图发送一些文件时,服务器正在创建它所能创建的所有线程。在这种情况下4,因此: static Semaphore semaphore = new Semaphore(4); 这是我的线程类,里面发生了什么 public class MyRunnable

我正在使用套接字开发应用程序。客户端正在监视特定目录,当用户在其中添加文件时,客户端通过套接字将该文件发送到服务器端的特定目录。 现在我已经实现了信号量,使许多文件同时发送到服务器。 这就是我的问题开始的地方。我正在使用while循环,当客户端试图发送一些文件时,服务器正在创建它所能创建的所有线程。在这种情况下4,因此:

static Semaphore semaphore = new Semaphore(4); 
这是我的线程类,里面发生了什么

public class MyRunnable implements Runnable {

        String name;

        public MyRunnable(String name) {
            this.name = name;
        }

        private void saveFile(String path) throws IOException {

            byte[] buffer = new byte[4096]; //4096 16384

            String fileName = dis.readUTF();
            int fileSize = (int) dis.readLong();

            int read = 0;
            int totalRead = 0;

            FileOutputStream fos = new FileOutputStream(path + fileName);
            System.out.println("Name of the file " + fileName);

            while ((read = dis.read(buffer, 0, Math.min(buffer.length, fileSize))) > 0) {
                totalRead += read;
                fileSize -= read;
                System.out.println("Read" + totalRead + " bytes.");
                fos.write(buffer, 0, read);
            }

        }

        public void run() {
            try {
                semaphore.acquire();
                System.out.println(name + " : got the permit!");
                System.out.println("available Semaphore permits : "
                        + semaphore.availablePermits());

                try {
                    saveFile(pathToFiles + login + "\\");
                } finally {

                    // calling release() after a successful acquire()
                    System.out.println(name + " : releasing lock...");
                    semaphore.release();
                    System.out.println(name + " : available Semaphore permits now: "
                            + semaphore.availablePermits());

                }

            } catch (IOException | InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
这是尚未发送任何内容时的输出:

Name0 : got the permit!
Name1 : got the permit!
Name3 : got the permit!
Name2 : got the permit!
available Semaphore permits : 0
available Semaphore permits : 0
available Semaphore permits : 0
available Semaphore permits : 0
这是我的客户机代码片段

public void watchDirectory(Path path) throws IOException, InterruptedException {
        WatchService watchService
                = FileSystems.getDefault().newWatchService();

        path.register(
                watchService,
                StandardWatchEventKinds.ENTRY_CREATE
                //     StandardWatchEventKinds.ENTRY_DELETE,
               // StandardWatchEventKinds.ENTRY_MODIFY
                );

        WatchKey key;
        while ((key = watchService.take()) != null) {
            for (WatchEvent<?> event : key.pollEvents()) {
                System.out.println(
                        "Event kind:" + event.kind()
                                + ". File affected: " + event.context());
                Runnable runnable = () -> {
                    System.out.println("Inside : " + Thread.currentThread().getName());
                    File file = new File(pathToFiles + login + "\\" + event.context());
                    try {
                        Thread.sleep(50);
                        sendFile(file);
                    } catch (IOException | InterruptedException e) {
                        e.printStackTrace();
                    }

                };
                
                System.out.println("Creating Thread...");
                Thread thread = new Thread(runnable);

                System.out.println("Starting Thread...");
                thread.start();
            }
            key.reset();
        }
    }

    public void sendFile(File file) throws IOException {

        FileInputStream fis = new FileInputStream(file);
        byte[] buffer = new byte[4096];  //4096 16384

        // writing name
        dos.writeUTF(file.getName());
        // writing length
        dos.writeLong(file.length());

        System.out.println(file.getName() + " " + file.length());

        int count;

        while ((count = fis.read(buffer)) > 0) {
            dos.write(buffer, 0, count);
        }

    }
public void watchDirectory(路径路径)引发IOException、InterruptedException{
监视服务监视服务
=FileSystems.getDefault().newWatchService();
路径寄存器(
值班服务,
StandardWatchEventTypes.ENTRY\u创建
//StandardWatchEventTypes.ENTRY\u删除,
//StandardWatchEventTypes.ENTRY\u修改
);
监视键;
while((key=watchService.take())!=null){
for(WatchEvent事件:key.pollEvents()){
System.out.println(
“事件种类:“+Event.kind()
+“.File受影响:”+event.context());
Runnable Runnable=()->{
System.out.println(“内部:+Thread.currentThread().getName());
File File=新文件(pathToFiles+login+“\\\”+event.context());
试一试{
睡眠(50);
sendFile(文件);
}捕获(IOException | InterruptedException e){
e、 printStackTrace();
}
};
System.out.println(“创建线程…”);
线程线程=新线程(可运行);
System.out.println(“起始线程…”);
thread.start();
}
键。重置();
}
}
公共void sendFile(文件文件)引发IOException{
FileInputStream fis=新的FileInputStream(文件);
byte[]buffer=新字节[4096];//4096 16384
//笔名
writeUTF(file.getName());
//书写长度
writeLong(file.length());
System.out.println(file.getName()+“”+file.length());
整数计数;
而((计数=fis.read(缓冲区))>0){
写(缓冲区,0,计数);
}
}
我想让一个线程处理客户端发送的一个文件。当客户端发送更多文件时,我希望线程能够同时工作。
有什么好办法吗?非常感谢您的帮助。

如果您想重新使用一组4个线程,最好的方法是使用固定线程池执行器:

ExecutorService threadPoolExecutor = Executors.newFixedThreadPool(4);

threadPoolExecutor.submit( new SomeRunnable() );
(有关此方法的更多信息,请参阅 )

在您的情况下,您将在目录监视程序之外创建ExecutorService,然后在监视程序代码中的某个位置将任务提交给它

有关如何在自己的线程中监视目录的示例,请参阅。根据该示例,您的目录观察程序类将如下所示:

public class DirWatcher implements Runnable {

    private final Path dir;
    private final WatchService watcher;
    private final WatchKey key;

    // thread pool for handling files in the watched directory
    ExecutorService threadPoolExecutor = Executors.newFixedThreadPool(4);

    @SuppressWarnings("unchecked")
    static <T> WatchEvent<T> cast(WatchEvent<?> event) {
        return (WatchEvent<T>) event;
    }

    public DirWatcher(Path dir) throws IOException {
        this.dir = dir;
        this.watcher = FileSystems.getDefault().newWatchService();
        this.key = dir.register(watcher, ENTRY_CREATE);
    }

    public void run() {
        try {
            for (;;) {
                WatchKey key = watcher.take();

                if (this.key != key) {
                    continue;
                }

                for (WatchEvent<?> event : key.pollEvents()) {
                    WatchEvent<Path> ev = cast(event);
                    String fileName = dir.resolve( ev.context() ).toString();

                    // handle event
                    threadPoolExecutor.submit( new SomeTask( fileName ) );
                }

                // reset key
                if (!key.reset()) {
                    break;
                }
            }
        } catch (InterruptedException x) {
            return;
        }
    }
}

现在,您的目录监视程序线程正在后台运行,并将启动新线程(最多4个)以处理监视目录中新文件的外观。同时,您还可以在主线程中执行其他工作。

如果您是使用单线程原理进行编程,为什么还要使用线程呢?也许我写得不太明白,但我希望每个客户端发送的文件都启动一个线程。我希望线程同时工作。那么你期望什么呢?主代码创建无限多的线程并启动它们。为什么你不认为计算机会创建无限多的线程并启动它们,当你告诉它这样做的时候?我知道它在做什么。我只是不知道如何让它按照我想要的方式工作。这就是为什么我在这里问了一个问题。我试图在循环中添加一些标志或if条件,但没有成功。如果你有任何想法如何启动一个线程每个文件从客户端发送让我知道。
public class DirWatcher implements Runnable {

    private final Path dir;
    private final WatchService watcher;
    private final WatchKey key;

    // thread pool for handling files in the watched directory
    ExecutorService threadPoolExecutor = Executors.newFixedThreadPool(4);

    @SuppressWarnings("unchecked")
    static <T> WatchEvent<T> cast(WatchEvent<?> event) {
        return (WatchEvent<T>) event;
    }

    public DirWatcher(Path dir) throws IOException {
        this.dir = dir;
        this.watcher = FileSystems.getDefault().newWatchService();
        this.key = dir.register(watcher, ENTRY_CREATE);
    }

    public void run() {
        try {
            for (;;) {
                WatchKey key = watcher.take();

                if (this.key != key) {
                    continue;
                }

                for (WatchEvent<?> event : key.pollEvents()) {
                    WatchEvent<Path> ev = cast(event);
                    String fileName = dir.resolve( ev.context() ).toString();

                    // handle event
                    threadPoolExecutor.submit( new SomeTask( fileName ) );
                }

                // reset key
                if (!key.reset()) {
                    break;
                }
            }
        } catch (InterruptedException x) {
            return;
        }
    }
}
public static void watchThatDirectory(String dirName) throws IOException, InterruptedException {

    Path dir = Paths.get(dirName);
    DirWatcher watcher = new DirWatcher(dir);

    ExecutorService executor = Executors.newSingleThreadExecutor();
    Future<?> future = executor.submit(watcher);
    executor.shutdown();
}