【问题标题】:Unable to achive synchronization in multithreading无法在多线程中实现同步
【发布时间】:2015-12-13 05:32:33
【问题描述】:

我基本上是在尝试实现一个多人在线预订一辆出租车的真实示例。在我的代码中,我有 3 个类——出租车、客户和服务器。
必须有多个客户(线程)和一个出租车。但我无法做到这一点。每次我创建新客户时,都会创建一个新的出租车实例。
这是出租车类代码-

    public class taxi  {
        boolean BOOKED=false;
         String id;
        void book(){
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
            BOOKED=true;
            System.out.println("Customer "+Thread.currentThread().getName()+" BOOKED taxi");
        }

        void release(){
            BOOKED=false;
            System.out.println("Customer "+Thread.currentThread().getName()+" RELEASED taxi");
        }

        void setId(String id){
            this.id=id;
        }

        String getId(){
            return id;
        }

    }

客户类代码-

public class customer extends Thread {
     taxi t=new taxi();
        public  void run(){
            //System.out.println(t.hashCode());
            t.setId(Thread.currentThread().getName());
            System.out.println("Customer "+Thread.currentThread().getName()+" trying to BOOK taxi");
            t.book();
            System.out.println("Customer "+Thread.currentThread().getName()+" is currently USING taxi");

            try {


Thread.sleep(2000);
        } catch (InterruptedException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        System.out.println("Customer "+Thread.currentThread().getName()+" RELEASING taxi");
        t.release();
        try {
            Thread.sleep(3000);
        } catch (InterruptedException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        System.out.println("taxi used by customer "+Thread.currentThread().getName()+" set id to "+t.getId());
    }



}

服务器类代码-

public class server {

public static void main(String args[]){

         customer A=new customer();
         customer B=new customer();
         customer C=new customer();
         customer D=new customer();
        Thread t=new Thread();
         A.setName("A");
         B.setName("B");
         C.setName("C");
         D.setName("D");

         A.start();
         B.start();
         C.start();
         D.start();




    }


    }


这是我的输出-

Customer B trying to BOOK taxi
Customer D trying to BOOK taxi
Customer A trying to BOOK taxi
Customer C trying to BOOK taxi
Customer B BOOKED taxi
Customer A BOOKED taxi
Customer A is currently USING taxi
Customer D BOOKED taxi
Customer D is currently USING taxi
Customer B is currently USING taxi
Customer C BOOKED taxi
Customer C is currently USING taxi
Customer C RELEASING taxi
Customer C RELEASED taxi
Customer D RELEASING taxi
Customer D RELEASED taxi
Customer A RELEASING taxi
Customer A RELEASED taxi
Customer B RELEASING taxi
Customer B RELEASED taxi
taxi used by customer D set id to D
taxi used by customer C set id to C
taxi used by customer A set id to A
taxi used by customer B set id to B


如您所见,每辆出租车的 ID 不同,而不是相同。
请帮助。

【问题讨论】:

  • 你认为taxi t=new taxi(); 作为customer 中的一个字段有什么作用?
  • 它在客户中创建了一个出租车实例。我知道这是我的问题的根本原因,但我想不出任何其他方法。
  • 创建一个taxi 实例并在您的customer 实例之间共享。你以前学过构造函数参数吗?
  • 是的,我知道客户的论点。你能告诉我这样做的确切代码吗?
  • 不幸的是,没有。使用构造函数参数在每个 customer 实例中设置 taxi 字段。使用相同的 taxi 实例作为您创建的每个 customer 的参数。

标签: java multithreading synchronization java-threads


【解决方案1】:

关于您的代码的一些要点:

  1. 您应该只创建 Taxi 类的单个实例,并从 Customer 类中删除出租车实例变量,并在服务器类中实例化 Taxi。
  2. 将您的客户类更改为在共享出租车上工作。您可以在 Customer 类中创建参数化构造函数来初始化共享出租车。
  3. setId 应该在方法 book 中调用,这样出租车的 Id 只能由想要预订出租车的线程更改。

您可以在Taxi类中通过这种方式使用等待/通知机制来实现同步:

public class Taxi {
    Boolean BOOKED = false;
    String id;

    void book() throws InterruptedException {
        synchronized (this) {
            while (BOOKED) {
                this.wait();
            }
            try {
                setId(Thread.currentThread().getName());
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            BOOKED = true;
            System.out.println("Customer " + Thread.currentThread().getName() + " BOOKED taxi");
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        }
    }

    void release() throws InterruptedException {
        synchronized (this) {
            BOOKED = false;
            System.out.println("Customer " + Thread.currentThread().getName() + " RELEASED taxi");
            this.notifyAll();
        }
    }

    void setId(String id) throws InterruptedException {
        System.out.println("SETTING ID TO CUSTOMER " + Thread.currentThread().getName());
        this.id = id;
    }

    String getId() {
        return id;
    }
}

客户:

   public class Customer extends Thread {
    Taxi taxi;

    public Customer(Taxi taxi){
        this.taxi = taxi;
    }

    public  void run(){
        //System.out.println(t.hashCode());

        System.out.println("Customer "+Thread.currentThread().getName()+" trying to BOOK taxi");
        try {
            taxi.book();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("Customer "+Thread.currentThread().getName()+" is currently USING taxi");

        try {
            Thread.sleep(2000);
        } catch (InterruptedException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        System.out.println("Customer "+Thread.currentThread().getName()+" RELEASING taxi");
        try {
            taxi.release();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        try {
            Thread.sleep(3000);
        } catch (InterruptedException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }
}

【讨论】:

  • 我猜你误解了这个问题。这里的问题是我最终拥有出租车类的多个实例,因为出租车类充当我的数据,所以我不能拥有它的多个实例。
  • 您应该只创建一个 Taxi 类的实例,并从 Customer 类中删除出租车实例变量,并在服务器类中实例化 Taxi
  • 好的。那么我如何进一步使用该实例,以便所有线程都在同一个实例上工作
  • 看看上面的答案
【解决方案2】:

我认为,出租车课不必是一个线程。通过将出租车类作为所有其他客户线程之间的共享资源(具有同步方法的单吨),我们可以在多线程中实现预期的同步。

【讨论】:

  • 你能告诉我如何在这里使用wait()和notify()等方法
【解决方案3】:

为什么您每次都在客户中创建新出租车?问题是:taxi t=new taxi();。只需通过构造函数传递出租车或使其成为全局或类似的东西。这样,每个客户都将使用相同的出租车。此外,线程是危险的,所以你应该非常小心它们。你没有任何同步。我建议您不了解如何正确使用线程。我建议您阅读synchronizevolatilewaitnotifynotifyAll 并尝试一些基本示例。我认为前两个在Head First Java 中得到了很好的描述。 题外话:命名变量和方法时应遵循约定。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2017-12-08
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多