在我的例子中,Synchronized和Lock有什么区别?

时间:2013-11-22 15:40:40

标签: java multithreading synchronization locking

我使用Locksynchronized编写了一个简单的代码来模拟并发。

源代码如下:

任务类包含一个名为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 --> 

上面的示例使用Locksynchronized来运行任务,我在这里有一些问题:

Q1:同步示例中的时间戳,它反映了3个线程之间的互斥锁。但为什么Lock示例中的经过时间相同?我不知道为什么。

Q2:我的示例中synchronizedLock之间有什么区别?

请帮我解决这两个问题。

2 个答案:

答案 0 :(得分:2)

首先,使用synchronized的示例设想不合理:在对象“A”上进行同步是一个非常糟糕的主意。请改用以下习语:

private final Object lock = new Object();

public void run() {
    synchronized (lock) {
        doSomething();
    }
}

这样做更好,因为通过隐藏外部对象的锁,您可以封装同步协议,从而实现更安全的同步策略。

现在,synchronizedjava.util.concurrent.locks.Lock之间的区别在于前者是同步原语,而后者是更高级别的锁定构造,它提供的操作比synchornized更精细。

您可以查看更多信息,尤其是http://docs.oracle.com/javase/7/docs/api/java/util/concurrent/locks/Lock.htmlhttp://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实现,或者将您的锁定为静态字段