2016.6.21笔记(1)-多线程同步

来源:互联网 发布:java版qq是什么意思 编辑:程序博客网 时间:2024/06/16 03:03

同步代码块

Java多线程支持引入了同步监视器来解决多线程安全,同步监视器的常用方法就是同步代码块。

Synchronized(obj){      //...同步代码块  } 

括号中的obj就是同步监视器:上面的语句表示:线程开始执行同步代码块之前,必须先获得对同步监视器的锁定。这就意味着任何时刻只能有一条线程可以获得对同步监视器的锁定,当同步代码块执行结束后,该线程自然释放了对该同步监视器的锁定。
虽然java中对同步监视器使用的对象没有任何要求,但根据同步监视器的目的:阻止两条线程对同一个共享资源进行并发访问所以一般将可能被并发访问的共享资源充当同步监视器

public void run() {        synchronized (accout) {            // 账户余额大于取款金额时            if (accout.getBalance() >= drawAmount) {                // 取款成功                System.out                        .println(Thread.currentThread().getName() + accout.getAccoutName() + "取款成功:吐出钞票:" + drawAmount);                // 修改余额                accout.setBalance(accout.getBalance() - drawAmount);                System.out.println("当前余额为:" + accout.getBalance());            }            // 账户金额不够时            else {                System.out.println("账户金额不够,您的余额只有" + accout.getBalance());            }        }    }

同步方法

synchronized可以修饰方法,代码块。不能修饰属性和构造方法.
除了同步代码块外还可以使用synchronized关键字来修饰方法,那么这个修饰过的方法称为同步方法。对于同步方法来说,无需显式指定同步监视器,同步方法的同步监视器是this,也就是该对象本身,也就是上面TestDraw中定义的Accout类型的acct。

public void run() {        draw();    }    public synchronized void draw() {        if (accout.getBalance() >= drawAmount) {            // 取款成功            System.out.println(Thread.currentThread().getName() + accout.getAccoutName() + "取款成功:吐出钞票:" + drawAmount);            // 修改余额            accout.setBalance(accout.getBalance() - drawAmount);            System.out.println("当前余额为:" + accout.getBalance());        }        // 账户金额不够时        else {            System.out.println("账户金额不够,您的余额只有" + accout.getBalance());        }    }

这里最好是将draw()方法写到Accout中,而不是像之前将取钱内容保存在run方法中,这种做法才更符合面向对象规则中的DDD(Domain Driven Design领域驱动设计)
对于可变类的同步会降低程序运行效率。不要对线程安全类德所有方法进行同步,只对那些会改变共享资源的方法同步。
单线程环境(可以使用线程不安全版本保证性能) 多线程环境(线程安全版本)。

同步监视器的锁定什么时候释放

  1. 当前线程的同步方法,同步块执行结束。当前线程释放同步监视器
  2. 在同步方法,块中遇到break,return终止了该代码块,方法.释放
  3. 在代码块,方法中出现Error,Exception
  4. 执行同步时,程序执行了同步监视器对象的wait()方法,则当前线程暂停,释放

同步监视器的锁定在以下情况不会被释放

  1. 执行同步时,程序调用Thread.sleep(),Thread.yield()方法来暂停当前线程的执行,不会释放
  2. 执行同步时,其他线程调用了该线程的suspend方法将该线程挂起,不会释放(但是尽量避免使用suspend和resume来控制线程,容易导致死锁)
0 0