问题描述
我有以下工人阶级 -
public class Worker implements Runnable {
private int workId;
public Worker(int workId) {
this.workId = workId;
}
private int count = 0;
private synchronized void increment() {
System.out.println("Work id: " + workId);
System.out.println("Incrementing...");
Thread.sleep(5000);
count++;
System.out.println("Incremented");
}
@Override
public void run() {
increment();
}
}
ExecutorService executorService = Executors.newFixedThreadPool(2);
for (int i = 1; i <= 10; i++) {
executorService.submit(new Worker(i));
}
executorService.shutdown();
System.out.println("All tasks submitted");
executorService.awaitTermination(1,TimeUnit.DAYS);
System.out.println("All tasks completed");
此处 increment()
已同步。因此,当 1 个线程占用它时,另一个线程必须等待该线程离开锁。
但是当我使用 2 个线程的线程池提交工作时,两个线程似乎同时使用 increment()
。
那么这里如何强制两个线程一次只使用一个 increment()
方法?
解决方法
private synchronized void increment()
此方法锁定在 Object
级别工作,因此如果您有两个对象,它们在调用此方法时不会相互阻塞,因为每个对象都会调用它的自己的 increment()
方法(在同一个 Worker
实例上没有并发调用)。
为了避免不同的实例同时访问 increment()
方法,您需要在 Class
级别进行同步,当所有 Worker
实例的锁相同时才能实现。声明锁的一些选项:
-
共享
Object
public class Boss extends RichDad implements EarnLotsOfMoney { private final Object masterLock; public Boss() { masterLock = new Object(); } public Worker createWorker(int slaveId) { return new Worker(masterLock,slaveId); } //... }
是的,我知道愚蠢的例子..
public class Worker implements Runnable { private final Object lock; private int workId; public Worker(Object lock,int workId) { this.lock = lock; this.workId = workId; } private void increment() { synchronized(lock) /*lock holds the same reference in all instances*/ { //... } } @Override public void run() { increment(); } }
lock
仅创建一次,然后在创建 Worker
实例时作为参数传递。这将阻止从同一 Worker
创建的所有 Boss
实例(在这种方法中,lock
是一个非静态对象) .
-
它自己的
Class
public class Worker implements Runnable { private int workId; public Worker(int workId) { this.workId = workId; } private int count = 0; private void increment() { synchronized(Worker.class) /*class level lock here*/ { System.out.println("Work id: " + workId); System.out.println("Incrementing..."); Thread.sleep(5000); count++; System.out.println("Incremented"); } } @Override public void run() { increment(); } }
这将使用共享 Worker
class 作为锁来同步线程。