Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/353.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/multithreading/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java:线程,如何让它们都做一些事情_Java_Multithreading_Locking - Fatal编程技术网

Java:线程,如何让它们都做一些事情

Java:线程,如何让它们都做一些事情,java,multithreading,locking,Java,Multithreading,Locking,我试图用Java实现节点之间的通信。我通过为每个想要与服务器对话的节点创建一个新线程来实现这一点 当给定数量的节点(即已创建多个线程)连接到服务器时,我希望每个线程在添加到sharedCounter后执行其下一位代码 我认为我需要在共享变量上使用“锁”,以及类似signalAll或notifyAll之类的东西来启动所有线程,但我似乎不清楚这是如何工作的,也不清楚如何实现它 任何解释这些Java概念的帮助都将不胜感激:D 下面是我的代码的大致结构: import java.net.*; imp

我试图用Java实现节点之间的通信。我通过为每个想要与服务器对话的节点创建一个新线程来实现这一点

当给定数量的节点(即已创建多个线程)连接到服务器时,我希望每个线程在添加到sharedCounter后执行其下一位代码

我认为我需要在共享变量上使用“锁”,以及类似signalAll或notifyAll之类的东西来启动所有线程,但我似乎不清楚这是如何工作的,也不清楚如何实现它

任何解释这些Java概念的帮助都将不胜感激:D

下面是我的代码的大致结构:

import java.net.*;
import java.io.*;

public class Node {

    public static void main(String[] args) {
    ...
    // Chooses server or client launchers depend on parameters.
    ...
    }
}

class sharedResource {
    private int sharedCounter;

    public sharedResource(int i) {
        sharedCounter = i;
    }

    public synchronized void incSharedCounter() {
        sharedCounter--;
        if (sharedCounter == 0)
            // Get all threads to do something
    }
}

class Server {
    ...
        for (int i = 0; i < numberOfThreads; i++) {
            new serverThread(serverSocket.accept()).start();
        }
    ...
        sharedResource threadCount = new sharedResource(numberOfThreads);
    ...
}

class serverThread extends Thread {
...
//some code
Server.threadCount.incSharedCounter();
// Some more code to run when sharedCounte == 0
...
}

class Client {
...
}

这是一个广泛的话题。您可以尝试阅读Java中的并发性,即线程。这不是简单的解决方案;你必须设计一些东西。

这是一个广泛的话题。您可以尝试阅读Java中的并发性,即线程。这不是简单的解决方案;你必须设计一些东西。

     // 让所有线程都做一些事情

线程或者更确切地说是可运行的,您应该实现它,而不是扩展线程,它有一个run方法,其中包含它们应该执行的代码

一旦调用Threadstart,而Threadstart又调用Runnablerun,线程就会开始执行该操作

由于您似乎对Java中的多线程还不熟悉,因此我建议您阅读并发实用程序包的介绍,该程序包在Java5中引入,以便更容易实现并发操作


具体地说,您似乎在寻找一种暂停操作的方法,直到满足条件(在您的情况下,计数器已达到零)。关于这一点,您应该看看。

     // 让所有线程都做一些事情

线程或者更确切地说是可运行的,您应该实现它,而不是扩展线程,它有一个run方法,其中包含它们应该执行的代码

一旦调用Threadstart,而Threadstart又调用Runnablerun,线程就会开始执行该操作

由于您似乎对Java中的多线程还不熟悉,因此我建议您阅读并发实用程序包的介绍,该程序包在Java5中引入,以便更容易实现并发操作


具体地说,您似乎在寻找一种暂停操作的方法,直到满足条件(在您的情况下,计数器已达到零)。关于这一点,您应该看一个。

的确,主题很广泛,但我将尝试解释基本内容。更多的细节可以从各种各样的文章中阅读。其中一个是

最好将每条线视为赛跑者,即在比赛中并排奔跑的物理人。每个跑步者可以在跑步时执行任何任务。例如,在比赛中的某一时刻从桌上取一杯水。在身体上,他们不能同时喝同一杯酒,但在虚拟世界中,这可能是界线所在

例如,再举两名跑步者为例;他们每个人都必须在一条跑道上来回跑,并在每一端按一个由跑步者共享的按钮1'000'000次,该按钮只是每次增加一个计数器。当他们完成运行时,计数器的值是多少?在现实世界中,这将是2'000'000,因为跑步者不能同时按下按钮,他们会等待第一个先离开。。。除非他们为此而斗争。。。这正是两个线程所要做的。考虑这个代码:

public class ThreadTest extends Thread {
    static public final int TOTAL_INC = 1000000;

    static public int counter = 0;

    @Override
    public void run() {
        for (int i=0; i<TOTAL_INC; i++) {
            counter++;
        }
        System.out.println("Thread stopped incrementing counter " + TOTAL_INC + " times");
    }

    public static void main(String[] args) throws InterruptedException {
        Thread t1 = new ThreadTest();
        Thread t2 = new ThreadTest();

        t1.start();
        t2.start();

        t1.join();  // wait for each thread to stop on their own...
        t2.join();  // 

        System.out.println("Final counter is : " + counter + " which should be equal to " + TOTAL_INC * 2);
    }
}
偶尔,两个线程只会将相同的值增加两次;这称为竞争条件

同步run方法将不起作用,您必须使用一些锁定机制来防止这种情况发生。考虑run方法中的下列更改:

我们已将计数器与共享对象同步。这就像在一次只有一个运行者可以访问按钮之前放置队列一样

注:此锁定机构称为a。如果一次可以用N个线程访问一个资源,您可以考虑使用.< /p> 多线程也与死锁相关。是指两个线程相互等待另一个线程释放一些同步资源以继续。例如:

static public final int TOTAL_INC = 10;
static private int counter = 0;
static private Object lock = new Object();

static class Thread1 extends Thread {
    @Override
    public void run() {
        synchronized (lock) {
            for (int i=0; i<TOTAL_INC; i++) {
                try {
                    lock.wait();
                    counter++;
                    lock.notify();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
    }
}

static class Thread2 extends Thread {
    @Override
    public void run() {
        synchronized (lock) {
            for (int i=0; i<TOTAL_INC; i++) {
                try {
                    lock.notify();
                    counter--;
                    lock.wait();
                } catch (InterruptedException e) {
                    /* ignored */
                }
            }
        }
    }
}
线程1启动 线程2启动 线程1获取同步对象1 线程2获取同步对象2 线程2需要获取object2以继续被线程1锁定 线程1需要获取object1以继续被线程2锁定 程序挂起在死锁中 虽然有很多方法可以防止这种情况发生,但这取决于线程在做什么,以及它们是如何实现的。。。你应该特别了解这一点

注意:只有在对象为s时才能调用wait、notify和notifyAll方法 同步的。例如:

static public final int TOTAL_INC = 10;
static private int counter = 0;
static private Object lock = new Object();

static class Thread1 extends Thread {
    @Override
    public void run() {
        synchronized (lock) {
            for (int i=0; i<TOTAL_INC; i++) {
                try {
                    lock.wait();
                    counter++;
                    lock.notify();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
    }
}

static class Thread2 extends Thread {
    @Override
    public void run() {
        synchronized (lock) {
            for (int i=0; i<TOTAL_INC; i++) {
                try {
                    lock.notify();
                    counter--;
                    lock.wait();
                } catch (InterruptedException e) {
                    /* ignored */
                }
            }
        }
    }
}

事实上,这个主题很广泛,但我将尝试解释基本内容。更多的细节可以从各种各样的文章中阅读。其中一个是

最好将每条线视为赛跑者,即在比赛中并排奔跑的物理人。每个跑步者可以在跑步时执行任何任务。例如,在比赛中的某一时刻从桌上取一杯水。在身体上,他们不能同时喝同一杯酒,但在虚拟世界中,这可能是界线所在

例如,再举两名跑步者为例;他们每个人都必须在一条跑道上来回跑,并在每一端按一个由跑步者共享的按钮1'000'000次,该按钮只是每次增加一个计数器。当他们完成运行时,计数器的值是多少?在现实世界中,这将是2'000'000,因为跑步者不能同时按下按钮,他们会等待第一个先离开。。。除非他们为此而斗争。。。这正是两个线程所要做的。考虑这个代码:

public class ThreadTest extends Thread {
    static public final int TOTAL_INC = 1000000;

    static public int counter = 0;

    @Override
    public void run() {
        for (int i=0; i<TOTAL_INC; i++) {
            counter++;
        }
        System.out.println("Thread stopped incrementing counter " + TOTAL_INC + " times");
    }

    public static void main(String[] args) throws InterruptedException {
        Thread t1 = new ThreadTest();
        Thread t2 = new ThreadTest();

        t1.start();
        t2.start();

        t1.join();  // wait for each thread to stop on their own...
        t2.join();  // 

        System.out.println("Final counter is : " + counter + " which should be equal to " + TOTAL_INC * 2);
    }
}
偶尔,两个线程只会将相同的值增加两次;这称为竞争条件

同步run方法将不起作用,您必须使用一些锁定机制来防止这种情况发生。考虑run方法中的下列更改:

我们已将计数器与共享对象同步。这就像在一次只有一个运行者可以访问按钮之前放置队列一样

注:此锁定机构称为a。如果一次可以用N个线程访问一个资源,您可以考虑使用.< /p> 多线程也与死锁相关。是指两个线程相互等待另一个线程释放一些同步资源以继续。例如:

static public final int TOTAL_INC = 10;
static private int counter = 0;
static private Object lock = new Object();

static class Thread1 extends Thread {
    @Override
    public void run() {
        synchronized (lock) {
            for (int i=0; i<TOTAL_INC; i++) {
                try {
                    lock.wait();
                    counter++;
                    lock.notify();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
    }
}

static class Thread2 extends Thread {
    @Override
    public void run() {
        synchronized (lock) {
            for (int i=0; i<TOTAL_INC; i++) {
                try {
                    lock.notify();
                    counter--;
                    lock.wait();
                } catch (InterruptedException e) {
                    /* ignored */
                }
            }
        }
    }
}
线程1启动 线程2启动 线程1获取同步对象1 线程2获取同步对象2 线程2需要获取object2以继续被线程1锁定 线程1需要获取object1以继续被线程2锁定 程序挂起在死锁中 虽然有很多方法可以防止这种情况发生,但这取决于线程在做什么,以及它们是如何实现的。。。你应该特别了解这一点

注意:只有在同步对象时才能调用wait、notify和notifyAll方法。例如:

static public final int TOTAL_INC = 10;
static private int counter = 0;
static private Object lock = new Object();

static class Thread1 extends Thread {
    @Override
    public void run() {
        synchronized (lock) {
            for (int i=0; i<TOTAL_INC; i++) {
                try {
                    lock.wait();
                    counter++;
                    lock.notify();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
    }
}

static class Thread2 extends Thread {
    @Override
    public void run() {
        synchronized (lock) {
            for (int i=0; i<TOTAL_INC; i++) {
                try {
                    lock.notify();
                    counter--;
                    lock.wait();
                } catch (InterruptedException e) {
                    /* ignored */
                }
            }
        }
    }
}

多线程不是Java的概念,它存在于许多编程语言中。在我看来,Java可能是最容易使用线程的一种。多线程不是Java的概念,它存在于许多编程语言中。在我看来,Java可能是使用threadsWell最容易的方法之一,Java.util.concurrent包确实提供了一些简单的解决方案。如果您可以使用其中一个,那么您根本不需要使用线程、等待/通知和直接同步。对于特定问题,可以。设计的一部分是识别您的问题,并尝试用已知解决方案的问题来表达它:绝对不要重新发明轮子。好吧,java.util.concurrent包确实提供了一些现成的解决方案。如果您可以使用其中一个,那么您根本不需要使用线程、等待/通知和直接同步。对于特定问题,可以。设计的一部分是识别您的问题,并尝试用已知解决方案的问题来表达它:绝对不要重新发明方向盘。不错的一个,但我认为可能更符合他的需要。顺便说一句:并发教程是可用的。实现Runnable而不是扩展线程有什么好处?@Serplat:保持Runnable和Runner的区别。此外:实现与扩展的所有常见优缺点也适用。特别是,在Java中,您只能扩展一个类,但可以实现任意多个接口;另一方面,接口不能指定任何数据。就JVM实现而言,这实际上是Java首先区分接口和抽象类的一个重要原因:如果数据来自继承链,而不是继承树或更糟糕的图形,那么将数据缝合在一起就更容易了。@Karl Knechtel:在这种情况下不是这样。并没有理由仅仅为了实现它的run方法而对线程进行子类化。很好的一个,但我认为这可能更符合他的需要。顺便说一句:并发教程是可用的。实现Runnable而不是扩展线程有什么好处?@Serplat:保持Runnable和Runner的区别。此外:实现与扩展的所有常见优缺点也适用。特别是,在Java中,您只能扩展一个类,但可以实现任意多个接口;另一方面,接口不能指定任何数据。就JVM实现而言,这实际上是Java为什么首先区分接口和抽象类的一个重要原因:更容易将
如果数据来自继承链,而不是继承树,或者更糟的是,来自图形,则将数据合并到一起。@Karl Knechtel:在这种情况下不是。没有理由仅仅为了实现线程的run方法而对线程进行子类化。非常感谢您的回答。清楚地描述线程的工作方式对理解和使用线程有很大帮助。我选择另一个答案是正确的,因为它解决了我遇到的具体问题,但是你的答案非常适用于我的线程工作。我以为你只需要线程方面的一般帮助:这里我添加了一个可能的例子,用于CountDownLatch类,以满足你的需要非常感谢你的回答。清楚地描述线程的工作方式对理解和使用线程有很大帮助。我选择另一个答案是正确的,因为它解决了我遇到的特定问题,但是你的答案非常适用于我的线程工作。我认为你只需要线程方面的一般帮助:这里我添加了一个可能的示例,用于CountDownLatch类,以满足你的需要