ReentrantLock-lock.unlock()不会释放锁定

时间:2019-04-06 01:38:34

标签: java multithreading concurrency

我正在尝试创建一个具有单个任务生产者(老板)和多个任务使用者(雇员)的应用程序。老板会不时添加更多任务,并且由员工来清除任务队列。问题如下:只有一个消费者正在完成所有工作,一旦完成,其他消费者就开始工作。

我尝试使用ReentrantLock,但似乎没有任何改变。

package threads;

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.locks.ReentrantLock;

public class Store {

    public static ReentrantLock lock = new ReentrantLock();


    public static void main(String[] args) {
        AtomicInteger tasksList = new AtomicInteger(7);
        Runnable boss = () -> {
            System.out.println("Boss: Good morning.");
            List<Runnable> employeeList = generateEmployeesList(5, tasksList);
            for (Runnable employee : employeeList) {
                employee.run();         
            }
            while(tasksList.get() > 0) {

                try {
                    lock.lock();
                    System.out.println("Work more!");
                    tasksList.incrementAndGet();

                } finally {
                    lock.unlock();
                    try {
                        Thread.sleep(1500);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }
            System.out.println("Boss: Time to go home.");
        };

        System.out.println("= Starting =");
        boss.run();

    }

    public static List<Runnable> generateEmployeesList(int amountOfEmployees, AtomicInteger tasksList){
        List<Runnable> employeeList = new ArrayList<Runnable>();
        for (int i = 0; i < amountOfEmployees; i++) {
            employeeList.add(createEmployee(i+1, tasksList));
        }
        return employeeList;
    }

    public static Runnable createEmployee(int employeeNumber, AtomicInteger tasksList) {
        return () -> {
            System.out.println("Thread #" + (employeeNumber) + " Started. Missing tasks: " + tasksList.get());
            while(tasksList.get() > 0) {

                try {
                    lock.lock();
                    System.out.println("Thread #" + (employeeNumber) + ". Task completed: " + tasksList.decrementAndGet() +" tasks left.");
                } finally {
                    lock.unlock();
                    try {
                        Thread.sleep(1000);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }

            }
            System.out.println("Thread #" + (employeeNumber) +": Finished.");
        };
    }

}

结果(错误):

= Starting =
Boss: Good morning.
Thread #1 Started. Missing tasks: 7
Thread #1. Task completed: 6 tasks left.
Thread #1. Task completed: 5 tasks left.
Thread #1. Task completed: 4 tasks left.
Thread #1. Task completed: 3 tasks left.
Thread #1. Task completed: 2 tasks left.
Thread #1. Task completed: 1 tasks left.
Thread #1. Task completed: 0 tasks left.
Thread #1: Finished.
Thread #2 Started. Missing tasks: 0
Thread #2: Finished.
Thread #3 Started. Missing tasks: 0
Thread #3: Finished.
Thread #4 Started. Missing tasks: 0
Thread #4: Finished.
Thread #5 Started. Missing tasks: 0
Thread #5: Finished.
Boss: Time to go home.

预期结果(随机消费者减少任务变量):

= Starting =
Boss: Good morning.
Thread #4 Started. Missing tasks: 7
Thread #4. Task completed: 6 tasks left.
Thread #2 Started. Missing tasks: 6
Thread #2. Task completed: 5 tasks left.
Thread #4. Task completed: 4 tasks left.
Thread #1 Started. Missing tasks: 4
...
Thread #1: Finished.
Thread #2: Finished.
Thread #3: Finished.
...
Boss: Time to go home.

关于我在做什么错的任何想法?我该怎么解决我的问题?

我修改了应用程序以使用线程而不是Runnables。但是,我仍然遇到同样的问题。

class Lock {
    private static final ReentrantLock lock = new ReentrantLock();
    public static final ReentrantLock getLock() {
        return lock;
    }
}

public class Store {


    public static void main(String[] args) {    
        Boss b = new Boss(5, 7);
        b.start();
    }

    public static List<Thread> generateEmployeesList(int amountOfEmployees, AtomicInteger tasksList){
        List<Thread> employeeList = new ArrayList<Thread>();
        for (int i = 0; i < amountOfEmployees; i++) {
            employeeList.add(employeeFactory(i+1, tasksList));
        }
        return employeeList;
    }


    public static Thread employeeFactory(int employeeNumber, AtomicInteger tasksList) {
        return new Employee(employeeNumber, tasksList);
    }


}

class Employee extends Thread {
    int number = 0;
    AtomicInteger tasksList;
    public Employee(int number, AtomicInteger tasksList) {
        this.number = number;
        this.tasksList = tasksList;
    }
    @Override
    public void start() {
        System.out.println("Thread #" + number + " Started. Missing tasks: " + tasksList.get());
        while(tasksList.get() > 0) {

            try {
                Lock.getLock().lock();
                System.out.println("Thread #" + number + ". Task completed: " + tasksList.decrementAndGet() +" tasks left.");
            } finally {
                Lock.getLock().unlock();
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }

        }
        System.out.println("Thread #" + number +": Finished.");
    }

}

class Boss extends Thread {
    int employees = 0;
    AtomicInteger tasks;

    public Boss(int employees, int numberOfTasks) {
        this.employees = employees;
        this.tasks = new AtomicInteger(numberOfTasks);
    }

    public void start() {
        List<Thread> employeeList = Store.generateEmployeesList(employees, tasks);
        System.out.println("Boss: Good Morning!");
        for (Thread employee : employeeList) {
            employee.start();
        }
        while(tasks.get() > 0 ) {
            Lock.getLock().lock();
            try {
            System.out.println("Keep working!");
            tasks.incrementAndGet();
            } finally {
                Lock.getLock().unlock();
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }

    }
}

1 个答案:

答案 0 :(得分:0)

此代码存在多个问题。您误会了如何使用Runnable。 Runnable#run()方法仅运行在当前线程中创建的代码。如果需要某种并行性,则必须创建一个单独的线程来运行它们。

// Change this
employee.start();
// to this:
Thread t = new Thread(employee);
t.start();

第二,如评论员所述,您没有正确锁定对原子的访问。因此,即使它在单个操作中是线程安全的,但在多个调用之间仍然不一致,尤其是如果您的行为取决于先前的结果(您这样做)。这就是为什么如果您在上方进行了单个更改,则会看到类似以下的输出:

= Starting =
Boss: Good morning.
Work more!
Thread #2 Started. Missing tasks: 7
Thread #1 Started. Missing tasks: 8
Thread #4 Started. Missing tasks: 7
Thread #3 Started. Missing tasks: 7
Thread #1. Task completed: 7 tasks left.
Thread #5 Started. Missing tasks: 7
Thread #5. Task completed: 6 tasks left.
Thread #2. Task completed: 5 tasks left.
Thread #4. Task completed: 4 tasks left.
Thread #3. Task completed: 3 tasks left.
Thread #5. Task completed: 2 tasks left.
Thread #1. Task completed: 1 tasks left.
Thread #2. Task completed: 0 tasks left.
Thread #4. Task completed: -1 tasks left.
Thread #3. Task completed: -2 tasks left.
Boss: Time to go home.
Thread #5: Finished.
Thread #1: Finished.
Thread #4: Finished.
Thread #2: Finished.
Thread #3: Finished.

在观察到还有任务之间

tasksList.get() > 0

“完成”一项任务

tasksList.incrementAndGet();

另一个线程可能承担了一项任务。这就是您看到的负数计数。这些操作必须都存在于循环中,或者必须使用某些其他同步方法,例如内置的对象同步方法:

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.locks.ReentrantLock;

public class Store {

    public static Object sync = new Object();

    public static void main(String[] args) {
        AtomicInteger tasksList = new AtomicInteger(7);
        Runnable boss = () -> {
            System.out.println("Boss: Good morning.");
            List<Runnable> employeeList = generateEmployeesList(5, tasksList);
            for (Runnable employee : employeeList) {
                Thread t = new Thread(employee);
                t.start();
            }

            synchronized (sync) {
                while(tasksList.get() > 0) {
                    try {                        
                        System.out.println("Work more!");
                        tasksList.incrementAndGet();
                    } finally {
                        try {
                            sync.wait(1500);
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                    }
                }
            }

            System.out.println("Boss: Time to go home.");
        };

        System.out.println("= Starting =");
        boss.run();

    }

    public static List<Runnable> generateEmployeesList(int amountOfEmployees, AtomicInteger tasksList){
        List<Runnable> employeeList = new ArrayList<Runnable>();
        for (int i = 0; i < amountOfEmployees; i++) {
            employeeList.add(createEmployee(i+1, tasksList));
        }
        return employeeList;
    }

    public static Runnable createEmployee(int employeeNumber, AtomicInteger tasksList) {
        return () -> {
            System.out.println("Thread #" + (employeeNumber) + " Started. Missing tasks: " + tasksList.get());
            synchronized (sync) {
                while (tasksList.get() > 0) {
                    try {
                        System.out.println("Thread #" + (employeeNumber) + ". Task completed: "
                                + tasksList.decrementAndGet() + " tasks left.");
                    } finally {
                        try {
                            sync.wait(1000);
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                    }
                }
            }
            System.out.println("Thread #" + (employeeNumber) +": Finished.");
        };
    }
}

屈服:

= Starting =
Boss: Good morning.
Thread #2 Started. Missing tasks: 7
Thread #3 Started. Missing tasks: 7
Work more!
Thread #4 Started. Missing tasks: 7
Thread #1 Started. Missing tasks: 7
Thread #3. Task completed: 7 tasks left.
Thread #5 Started. Missing tasks: 8
Thread #2. Task completed: 6 tasks left.
Thread #5. Task completed: 5 tasks left.
Thread #1. Task completed: 4 tasks left.
Thread #4. Task completed: 3 tasks left.
Thread #2. Task completed: 2 tasks left.
Thread #1. Task completed: 1 tasks left.
Thread #3. Task completed: 0 tasks left.
Thread #4: Finished.
Thread #5: Finished.
Boss: Time to go home.
Thread #3: Finished.
Thread #2: Finished.
Thread #1: Finished.