我使用Lock
和synchronized
编写了一个简单的代码来模拟并发。
源代码如下:
任务类包含一个名为doSomething()
的方法,用于打印线程名称并执行已用时间。
import java.util.Calendar;
public class Task {
public void doSomething() {
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
StringBuilder sb = new StringBuilder();
//Thread Name
sb.append("Thread Name: ").append(Thread.currentThread().getName());
//Timestamp for the executing
sb.append(", elaspsed time: ").append(Calendar.getInstance().get(13)).append(" s ");
System.out.println(sb.toString());
}
}
TaskWithLock 类
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
public class TaskWithLock extends Task implements Runnable {
private final Lock lock = new ReentrantLock();
@Override
public void run() {
try {
lock.lock();
doSomething();
} finally {
lock.unlock();
}
}
}
TaskWithSync 类
public class TaskWithSync extends Task implements Runnable {
@Override
public void run() {
synchronized ("A") {
doSomething();
}
}
}
主要类
public class Main {
public static void runableTasks(Class<? extends Runnable> clz)
throws Exception {
ExecutorService service = Executors.newCachedThreadPool();
System.out.printf("<-- Start executing %s Task --> \n",
clz.getSimpleName());
// Start 3 threads
for (int i = 0; i < 3; i++) {
service.submit(clz.newInstance());
}
// Wait for some time, and then close the executor
TimeUnit.SECONDS.sleep(10);
System.out
.printf("<-- %s Tasks is complet --> \n", clz.getSimpleName());
service.shutdown();
}
public static void main(String[] args) throws Exception {
//Execute tasks with Lock
runableTasks(TaskWithLock.class);
//Execute tasks with Synchronized
//runableTasks(TaskWithSync.class);
}
}
第一次,通过调用方法 runableTasks(TaskWithSync.class);
执行Synchronized任务<-- Start executing TaskWithSync Task -->
Thread Name: pool-1-thread-1, elaspsed time: 28 s
Thread Name: pool-1-thread-3, elaspsed time: 30 s
Thread Name: pool-1-thread-2, elaspsed time: 32 s
<-- TaskWithSync Tasks is complet -->
第二次,通过调用方法 runableTasks(TaskWithLock.class)执行带锁的任务;
<-- Start executing TaskWithLock Task -->
Thread Name: pool-1-thread-3, elaspsed time: 23 s
Thread Name: pool-1-thread-2, elaspsed time: 23 s
Thread Name: pool-1-thread-1, elaspsed time: 23 s
<-- TaskWithLock Tasks is complet -->
上面的示例使用Lock
和synchronized
来运行任务,我在这里有一些问题:
Q1:同步示例中的时间戳,它反映了3个线程之间的互斥锁。但为什么Lock示例中的经过时间相同?我不知道为什么。
Q2:我的示例中synchronized
和Lock
之间有什么区别?
请帮我解决这两个问题。
答案 0 :(得分:2)
首先,使用synchronized
的示例设想不合理:在对象“A”上进行同步是一个非常糟糕的主意。请改用以下习语:
private final Object lock = new Object();
public void run() {
synchronized (lock) {
doSomething();
}
}
这样做更好,因为通过隐藏外部对象的锁,您可以封装同步协议,从而实现更安全的同步策略。
现在,synchronized
和java.util.concurrent.locks.Lock
之间的区别在于前者是同步原语,而后者是更高级别的锁定构造,它提供的操作比synchornized
更精细。
您可以查看更多信息,尤其是http://docs.oracle.com/javase/7/docs/api/java/util/concurrent/locks/Lock.html和http://docs.oracle.com/javase/7/docs/api/java/util/concurrent/locks/ReentrantLock.html。
答案 1 :(得分:1)
synchronized ("A")
这不是同步块的正确用法。在输入此同步块时,您创建了一个不同的String对象(在某些情况下),因此每个线程都有一个不同的锁定对象,并且不同步。正确使用可能就像
synchronized(this)
或
public class TaskWithSync extends Task implements Runnable {
private Object lock = new Object();
@Override
public void run() {
synchronized (lock) {
doSomething();
}
}
}
此外,您应该在不同的线程中使用单个Runnable实现,或者将您的锁定为静态字段