Java创建两个线程但只运行一个

时间:2018-04-18 12:39:02

标签: java multithreading concurrency synchronized

我可能早先问过here,而且缺乏理解和复杂,现在我以更容易理解的方式重写程序。

问题:

当我运行2个线程时,只有1个线程完成这项工作。

怀疑助手

我怀疑线程自己锁定,因此另一个线程无法访问它。

代码

初始化主要

    Shop shop = new Shop();
    CarGenerator carGenerator = new CarGenerator(shop);

    Mechanics mechanics1 = new Mechanics(shop, "Mechanics 1");
    Mechanics mechanics2 = new Mechanics(shop, "Mechanics 2");

    //Threads
    Thread CarThread = new Thread(carGenerator);
    Thread Mechanics1Thread = new Thread(mechanics1);
    Thread Mechanics2Thread = new Thread(mechanics2);


    CarThread.start();
    Mechanics1Thread.start();
    Mechanics2Thread.start();

在这里,我们可以看到2个线程正在创建并按预期工作。

现在机械师的功能是什么:

@Override
public void run() {
    while (true) {
        System.out.println("Working Thread: " + Thread.currentThread().getName());
        shop.CarFix(MechanicsName);
    }
}

线索:

这里我打印出有多少个线程,结果是2:

Working Thread: Thread-1
Working Thread: Thread-2

很好,现在两个线程都按预期运行,现在我将在商店工作无限。我不会削减以显示整个过程并更好地理解:

public void CarFix(String MechanicsName) {
    Car car;
    synchronized (ListCarEntry) {
    while (ListCarEntry.size() == 0) {
        try {
            ListCarEntry.wait();
        }   catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }

    try {
        Thread.sleep(2000);
    } catch (InterruptedException ex) {
        Logger.getLogger(Shop.class.getName()).log(Level.SEVERE, null, ex);
    }
    System.out.println("Working Thread: " + Thread.currentThread().getName());
    //Done 2 Sec Fixing
    //Release Now

    car = (Car) ((LinkedList<?>) ListCarEntry).poll();
    ((LinkedList<Car>) ListCarFix).offer(car);
    System.out.println("Car FIX: " + car.getCarName() + " being fixed by " + MechanicsName);

}

这里Thread只运行一个而不是之前的2个线程,结果是:

Working Thread: Thread-1
Car FIX: Car 1 being fixed by Mechanics 1

Working Thread: Thread-1
Car FIX: Car 2 being fixed by Mechanics 1

Working Thread: Thread-1
Car FIX: Car 3 being fixed by Mechanics 1

现在只有力学1修复,而力学2缺失。

线索2:

当我尝试删除SACEP FOR 2 SEC 时,结果就是我真正想要的结果:

Working Thread: Thread-1
Car FIX: Car 1 being fixed by Mechanics 1

Working Thread: Thread-2
Car FIX: Car 2 being fixed by Mechanics 2

Working Thread: Thread-1
Car FIX: Car 3 being fixed by Mechanics 1

这是我真正想要看到的。

问题:

如何确保线程按预期工作并具有睡眠功能?

对于直到最后阅读的人:

看到我不知道删除睡眠可能会解决问题,安静怪异..无论如何任何想法的人..并抱歉长期的问题。

修改

这是我的CarGenerator课程:

public class CarGenerator implements Runnable{
    Shop shop;

    public CarGenerator(Shop shop) {
        this.shop = shop;
    }

    @Override
    public void run() {

    int i = 0;
    while (true) {
        i++;

        Car car = new Car(shop, "Car " + i);

        try {
            Thread.sleep(1000);
        } catch (InterruptedException ex) {
            Logger.getLogger(CarGenerator.class.getName()).log(Level.SEVERE, null, ex);
        }

        Thread thCar = new Thread(car);
        thCar.start();

    }
    }

}

这个叫这个车的车把车开到车间:

public class Car implements Runnable{


    private String CarName;
    private Shop shop;


    public Car(Shop shop, String CarName) {
        this.shop = shop;
        this.CarName = CarName;               
    }

    public String getCarName() {
        return CarName;
    }

    @Override
    public void run() {
        //DO
        synchronized(this) {
        shop.CarEntrance(this);
        }


    }

}

这是汽车进入商店的地方

public void CarEntrance(Car car) {
    System.out.println("Entry: " + car.getCarName());

    if (ListCarEntry.size() == 10){
        System.out.println("Exit: " + car.getCarName() + "Exit the store, cause FULL");
        return;
    }

    ((LinkedList<Car>) ListCarEntry).offer(car);
    if (ListCarEntry.size() == 1) {
        synchronized(ListCarEntry) {
            ListCarEntry.notify();
        }

    }
}

如此处所示,我呼叫通知同步通知机械师正在等待车辆等待车辆进入。

2 个答案:

答案 0 :(得分:1)

这是一个非常奇怪的设置。您的机制是同步的线程,但同步是在Shop中完成的;你通常在线程本身同步。而且,如果您使用线程安全队列对象来管理要修复的汽车,那么您真的不需要显式同步。这使得它成为典型的生产者/消费者问题,商店是生产者,机械师是消费者。

class Shop {
    private static BlockingQueue<Integer> cars = new ArrayBlockingQueue<>();
    private static int carNumber;
    private static Random RANDOM = new Random();

    public static void main(String[] args) {

        // you can add more mechanics here
        int mechanicsCount = 2;
        for (int i = 0; i < mechanicsCount; i++) {
            new Thread(createMechanic(String.format("Mechanic %d", i))).start();
        }

        ScheduledExecutorService producingScheduler = Executors.newSingleThreadScheduledExecutor();
        // add a new car every 300 ms
        producingScheduler.scheduleAtFixedRate(() -> {
            try {
                cars.put(carNumber++);
            } catch (InterruptedException e) { }
        }, 0, 300, TimeUnit.MILLISECONDS);
    }

    // the concurrently running code
    private Runnable createMechanic(String name) {
        return () -> {
            try {
                while (true) {
                    // synchronization happens here: queue is thread-safe
                    Integer car = cars.take();
                    System.out.printf("repairing car %s in thread %s\n", car, Thread.currentThread().getName());
                    // take some time repairing
                    int timeToRepair = RANDOM.nextInt(500);
                    Thread.sleep(timeToRepair);
                    System.out.printf("car %s is repaired, took %s ms\n", car, timeToRepair);
                }
            } catch (InterruptedException e) { }
        };

    }
}

这样,机械师将在队列中等待下一辆车出现。

答案 1 :(得分:0)

对于解决方案,我只是从 CarFix函数移动了Thread.sleep:

public void CarFix(String MechanicsName) {
    Car car;
    synchronized (ListCarEntry) {
    while (ListCarEntry.size() == 0) {
        try {
            ListCarEntry.wait();
        }   catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }

    //There is No Sleep

    car = (Car) ((LinkedList<?>) ListCarEntry).poll();
    ((LinkedList<Car>) ListCarFix).offer(car);
    System.out.println("Car FIX: " + car.getCarName() + " being fixed by " + MechanicsName);

}

并将其移至力学课程

@Override
public void run() {
    while (true) {

    try {
        Thread.sleep(3000);
    } catch (InterruptedException ex) {
        Logger.getLogger(Shop.class.getName()).log(Level.SEVERE, null, ex);
    }
        shop.CarFix(MechanicsName);
    }
}

结果:

Entry: Car 1
Entry: Car 2

Working Thread: Thread-1
Working Thread: Thread-2
Car FIX: Car 1 being fixed by Mechanics 2
Car FIX: Car 2 being fixed by Mechanics 1

Entry: Car 3
Entry: Car 4
Entry: Car 5

Working Thread: Thread-1
Working Thread: Thread-2
Car FIX: Car 3 being fixed by Mechanics 1
Car FIX: Car 4 being fixed by Mechanics 2

我认为这辆车是2乘2的车,我真的不想要,我想要一个独立的力学,所以我试着将Cargenerator设置为10秒进行调试测试,结果:

Entry: Car 1
Working Thread: Thread-2
Car FIX: Car 1 being fixed by Mechanics 2

Entry: Car 2
Working Thread: Thread-1
Car FIX: Car 2 being fixed by Mechanics 1

Entry: Car 3
Working Thread: Thread-2
Car FIX: Car 3 being fixed by Mechanics 2

Entry: Car 4
Working Thread: Thread-1
Car FIX: Car 4 being fixed by Mechanics 1

现在这很公平,效果比预期好得多。

感谢所有的贡献,案例已关闭