您的位置:首页 > 运维架构 > Tomcat

TOMCAT 启动是出错:Error Filterstart

2010-08-19 16:27 330 查看
同步代码块:

文件并发被访问时容易造成异常。

同步代码块语法格式:

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()来释放锁,所以一段被锁保护的代码可以调用另一个被相同锁保护的方法。

本文出自 “java程序猿的博客” 博客,转载请与作者联系!
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: