黑马程序员技术交流社区

标题: 关于多线程的同步的问题 [打印本页]

作者: 华行天下    时间: 2013-9-28 12:32
标题: 关于多线程的同步的问题
本帖最后由 华行天下 于 2013-9-28 13:47 编辑

关于多线程的同步synchronized和lock有点混不太懂,不知道这两个什么分别什么时候用;希望得到大家的帮助;

作者: hanfei2511    时间: 2013-9-28 12:59
关于多线程的同步synchronized和lock有点混不太懂,不知道这两个什么分别什么时候用;希望得到大家的帮助;
关于这个问题,我想最普遍的解释(常常作为答案的)就是下面所说的:
主要相同点:Lock能完成synchronized所实现的所有功能
主要不同点:Lock有比synchronized更精确的线程语义和更好的性能。synchronized会自动释放锁,而Lock一定要求程序员手工释放,并且必须在finally从句中释放。
虽然不错,但是在我总结这方面的时候,我搜集了别人对这个问题更好更全的解释:
synchronized块的确不错,但是他有一些功能性的限制:
1. 它无法中断一个正在等候获得锁的线程,也无法通过投票得到锁,如果不想等下去,也就没法得到锁。
2.synchronized 块对于锁的获得和释放是在相同的堆栈帧中进行的。多数情况下,这没问题(而且与异常处理交互得很好),但是,确实存在一些更适合使用非块结构锁定的情况。
java.util.concurrent.lock 中的 Lock 框架是锁定的一个抽象,它允许把锁定的实现作为 Java 类,而不是作为语言的特性来实现。这就为 Lock 的多种实现留下了空间,各种实现可能有不同的调度算法、性能特性或者锁定语义。
JDK 官方文档中提到:
ReentrantLock是“一个可重入的互斥锁 Lock,它具有与使用 synchronized 方法和语句所访问的隐式监视器锁相同的一些基本行为和语义,但功能更强大。
ReentrantLock 将由最近成功获得锁,并且还没有释放该锁的线程所拥有。当锁没有被另一个线程所拥有时,调用 lock 的线程将成功获取该锁并返回。如果当前线程已经拥有该锁,此方法将立即返回。可以使用 isHeldByCurrentThread() 和 getHoldCount() 方法来检查此情况是否发生。 ”
简单来说,ReentrantLock有一个与锁相关的获取计数器,如果拥有锁的某个线程再次得到锁,那么获取计数器就加1,然后锁需要被释放两次才能获得真正释放。这模仿了 synchronized 的语义;如果线程进入由线程已经拥有的监控器保护的 synchronized 块,就允许线程继续进行,当线程退出第二个(或者后续) synchronized 块的时候,不释放锁,只有线程退出它进入的监控器保护的第一个 synchronized 块时,才释放锁。
ReentrantLock 类(重入锁)实现了 Lock ,它拥有与 synchronized 相同的并发性和内存语义,但是添加了类似锁投票、定时锁等候和可中断锁等候的一些特性。此外,它还提供了在激烈争用情况下更佳的性能。(换句话说,当许多线程都想访问共享资源时,JVM 可以花更少的时候来调度线程,把更多时间用在执行线程上。)
当然这不是我总结的,但我感觉很全面,当然原文中还有例子,你可以通过他的例子来理解上面的内容。原文还包括解释到此步还会存在的问题及解决方法,您如果感兴趣可以点击下面的链接:
http://www.java3z.com/cwbwebhome/article/article8/895.html
希望对您有帮助。

作者: a283398689    时间: 2013-9-28 13:39
下面是我给你写的代码 你自己读读 就明白
package num10;

import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantReadWriteLock;

// java 读写锁
class M

{

    private static Map<Integer, String> map = new HashMap<Integer, String>();

    private static M m = new M(map);

    public static M getInstance()

    {

        return m;

    }

    private final java.util.concurrent.locks.ReadWriteLock lock = new ReentrantReadWriteLock();

    private final Lock r = lock.readLock();

    private final Lock w = lock.writeLock();

    public M(Map<Integer, String> map) {

        this.map = map;

    }

    public String put(Integer key, String value) {

        System.out.println("waiting put");

        w.lock();

        try {

            System.out.println("processing put");

            try {

                Thread.sleep(5000l);

            } catch (InterruptedException e) {

                // TODO Auto-generated catch block

                e.printStackTrace();

            }

            return map.put(key, value);

        } finally {
            System.out.println("put finish");
            w.unlock();

        }

    }

    public synchronized String put1(Integer key, String value) {

        System.out.println("waiting put1");

        try {

            System.out.println("processing put1");

            try {

                Thread.sleep(5000l);

            } catch (InterruptedException e) {

                // TODO Auto-generated catch block

                e.printStackTrace();

            }

            return map.put(key, value);

        } finally {
            System.out.println("put1 finish");
        }

    }

    public String get(Object key) {

        System.out.println("waiting get");

        r.lock();

        try {

            System.out.println("processing get");

            try {

                Thread.sleep(5000l);

            } catch (InterruptedException e) {

                // TODO Auto-generated catch block

                e.printStackTrace();

            }

            return map.get(key);

        } finally {
            System.out.println("get finish");
            r.unlock();

        }

    }

    public synchronized String get1(Object key) {

        System.out.println("waiting get1");

        try {

            System.out.println("processing get1");

            try {

                Thread.sleep(5000l);

            } catch (InterruptedException e) {

                // TODO Auto-generated catch block

                e.printStackTrace();

            }

            return map.get(key);

        } finally {
            System.out.println("get1 finish");

        }

    }

}

public class ReadWriteLock implements Runnable

{

    private int i;

    private boolean get;

    ReadWriteLock(int i, boolean get)

    {

        this.i = i;

        this.get = get;

    }

    public void run()

    {

        M m = M.getInstance();

        if (get)

        {

            m.get1(new Integer(1));

        }

        else

        {

            m.put1(new Integer(1), "1");

        }

    }

    public static void main(String[] args)

    {

        boolean getfirst = false;

        ReadWriteLock c = new ReadWriteLock(0, !getfirst);

        Thread t = new Thread(c);

        t.start();

        ReadWriteLock c2 = new ReadWriteLock(1, getfirst);

        Thread t2 = new Thread(c2);

        t2.start();

    }

}
运行结果如下:

waiting get1
processing get1
get1 finish
waiting put1
processing put1
put1 finish

可以看出synchronized 关键字相当于 lock(M.class), 是将整个对象锁住,为提高效率,可以使用读写锁





欢迎光临 黑马程序员技术交流社区 (http://bbs.itheima.com/) 黑马程序员IT技术论坛 X3.2