网站开发工具的功能包括HTML或,网页设计与网站建设电话,大型门户网站建设价格,中国装修公司排行榜同步代码块#xff1a; 文件并发被访问时容易造成异常。 同步代码块语法格式#xff1a; synchronized(obj) { ... //此处的代码就是同步代码块 } obj是同步监视器 线程开始执行同步代码块之前#xff0c;必须先获得对同步监视器的锁定。 注#xff1a;任何时… 同步代码块 文件并发被访问时容易造成异常。 同步代码块语法格式 synchronized(obj) { ... //此处的代码就是同步代码块 } obj是同步监视器 线程开始执行同步代码块之前必须先获得对同步监视器的锁定。 注任何时刻只能有一条线程可以获得对同步监视器的锁定当同步代码块执行结束后该线程自然释放了对该同步监视器的锁定。 通常推荐使用可能被并发访问的共享资源充当同步监视器。 例 /* 模拟银行用户取钱问题 */ public class DrawThread extends Thread { //模拟用户帐户 private Account account; //当前取钱线程所希望取的钱数 private double drawAmount; public DrawThread(String name,Account account,double drawAmout) { super(name); this.account account; this.drawAmount drawAmount; } //当多条线程修改同一个共享数据时涉及安全问题 public void run() { //account作为同步监视器 synchronized(account) { //帐户余额大于取钱钱数 if(account.getBalance() drawAmount) { System.out.println(getName() 取钱成功吐出钞票 drawAmount); try { Thread.sleep(1); } catch(InterruptedException ex) { ex.printStackTrace(); } //修改余额 account.setBalance(account.getBalance() - drawAmount); System.out.println(\t余额为 account.getBalance()); } else { System.out.println(getName()取钱失败余额不足); } } //同步代码块结束该线程释放同步锁 } } 同步方法 同步方法就是使用synchronized关键字来修饰某个方法则该方法称为同步方法。 同步方法无需显示指出同步监视器同步方法的同步监视器就是this,也就是该方法本身。 例 public class Account { private String accountNo; private double balance; public Account(){} public Account(String accountNo,double balance) { this.accountNo accountNo; this.balance balance; } //此处省略了accountNo的setter和getter方法 //因此余额帐户不允许随便修改所以取消balance属性的setter方法 public double getBalance() { return this.balance; } //提供一个线程安全draw方法来完成取钱操作 public synchronized void draw(double drawAmount) { //帐户余额大于取钱数目 if(balance drawAmount) { //吐出钞票 System.out.println(Thread.currentThread().getName() 取钱成功吐出钞票 drawAmount); try { Thread.sleep(1); } catch(InterruptedException ex) { ex.printStackTrace(); } //修改余额 balance - drawAmount; System.out.println(\t 余额为 balance); } else { System.out.println(Thread.currentThread().getName() 取钱失败余额不足); } } //此处省略了hashCode和equals两个重写的方法。 ... } 注synchronized关键字可以修饰方法可以修饰代码块但不能修饰构造器属性等。 释放同步监视器的锁定 线程会在如下几种情况下释放对同步监视器的锁定 1.当前线程的同步方法、同步代码块执行结束当前线程即释放同步监视器。 2.当线程在同步代码块、同步方法中遇到break,return终止了该代码块、该方法的继续执行 当前线程将会释放同步监视器。 3.当线程在同步代码块、同步方法中出现了未处理的Error或Exception,导致了该代码块、该方法异常结束时将会释放同步监视器。 4.当线程执行同步代码块或同步方法时程序执行了同步监视器对象的wait()方法则当前线程暂停并释放同步监视器。 在下面情况下线程不会释放同步监视器 1、线程执行同步代码块或同步方法时程序调用Thread.sleep()、Thread.yield()方法来暂停当前线程的执行当前线程不会释放同步监视器。 2、线程执行同步代码块时其他线程调用了该线程的suspend方法将该线程挂起该线程不会释放同步监视器。应尽量避免 同步锁(Lock)使用方法 使用Lock对象的代码格式如下 //ReentrantLock 可重入锁 class X { //定义锁对象 private final ReentrantLock lock new ReentrantLock(); //.. //定义需要保证线程安全的方法 public void m() { //加锁 lock.locl(); try { //需要保证线程安全的代码 //...method body } //使用finally块来保证释放锁 finally { lock.unlock(); } } } 例 public class Account { //定义锁对象 private final ReentrantLock lock new ReentrantLock(); private String accountNo; private double balance; public Account(){}; public Account(String accountNo,double balance) { this.accountNo accountNo; this.balance balance; } //此处省略了accountNo的setter和getter方法 //因此帐户余额不允许随便修改所以取消balance属性的setter方法 public double getBalance() { return this.balance; } //提供一个线程安全draw方法来完成取钱操作 public void draw(double drawAmount) { //对同步锁进行加锁 lock.lock(); try { //帐户余额大于取钱数目 if(balance drawAmount) { //吐出钞票 System.out.println(Thread.currentThread().getName() 取钱成功吐出钞票 drawAmount); try { Thread.sleep(1); } catch(InterruptedException ex) { ex.printStackTrace(); } //修改余额 balance - drawAmount; System.out.println(\t 余额为 balance); } else { System.out.println(Thread.currentThread().getName()取钱失败余额不足); } } //使用finally块开确保释放锁 finally { lock.unlock(); } } //此处省略了hashCode和equals两个重写的方法。 ... } 注使用Lock与使用同步方法有点相似只是使用Lock时显示使用Lock对象作为同步锁而使用同步方式时系统饮式使用当前对象作为监视器同样符合“加锁-访问-释放锁”的操作模式而且使用Lock对象时每个Lock对象对应一个Account对象一样可以保证对于同一个Account对象同一时刻只能有一条线程能进入临界区。 ReentrantLock锁具有重入性也就是说线程可以对他已经加锁的ReentrantLock锁再次加锁线程在每次调用lock()加锁后必须显示调用unlock()来释放锁所以一段被锁保护的代码可以调用另一个被相同锁保护的方法。 转载于:https://blog.51cto.com/chengxuyuan/1034833