黑马程序员技术交流社区
标题:
线程安全问题
[打印本页]
作者:
冯鹏飞
时间:
2011-7-22 21:39
标题:
线程安全问题
为什么会有线程安全机制呢,看视频时不明白为什么要添加syncronized方法,希望能举例说明在什么情况下需要使用syncronized ?
作者:
匿名
时间:
2011-7-22 21:48
syncronized 就是一个监听器
由于cpu是时间片机制的。就是这个线程运行一会,跑到另一个线程上运行一会。
如果在第一个线程上刚操作了一个参数,又跑到另一个线程上再操作这个参数,再回到第一个线程上,那个现在的参数就不是原来的参数了吧
syncronized 就是起到一个,在第一个线程操作的时候,第二个线程不能操作这个线程的数据。从而保证了线程的同步。
java1.5之后又有了一个叫lock的接口。他的子类起到的作用和syncronized 差不多。通过它的luck和unlock方法可以比syncronized 更灵活。所以更推荐使用lock接口的子类
作者:
匿名
时间:
2011-7-24 09:38
:) 很简单的一个日常生活中的列子,一个账户给两个人用,每人都去取出这个账户的所有余额,如果一个线程取钱的操作刚好在账户余额减少之前就暂停,另外一个线程进入这个取钱的方法进行取钱,那么也就使这个账户的余额为负了
看如下的例子[code=java]public class Account
{
//封装账户编号、账户余额两个属性
private String accountNo;
private double balance;
public Account(){}
//构造器
public Account(String accountNo , double balance)
{
this.accountNo = accountNo;
this.balance = balance;
}
public void setAccountNo(String accountNo)
{
this.accountNo = accountNo;
}
public String getAccountNo()
{
return this.accountNo;
}
public void setBalance(double balance)
{
this.balance = balance;
}
public double getBalance()
{
return this.balance;
}
//下面两个方法根据accountNo来计算Account的hashCode和判断equals
public int hashCode()
{
return accountNo.hashCode();
}
public boolean equals(Object obj)
{
if (obj != null
&& obj.getClass() == Account.class)
{
Account target = (Account)obj;
return target.getAccountNo().equals(accountNo);
}
return false;
}
}[/code][code=java]public class DrawThread extends Thread
{
//模拟用户账户
private Account account;
//当前取钱线程所希望取的钱数
private double drawAmount;
public DrawThread(String name , Account account ,
double drawAmount)
{
super(name);
this.account = account;
this.drawAmount = drawAmount;
}
//当多条线程修改同一个共享数据时,将涉及到数据安全问题。
public void run()
{
//账户余额大于取钱数目
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() + "取钱失败!余额不足!");
}
}
}[/code][code=java]public class TestDraw
{
public static void main(String[] args)
{
//创建一个账户
Account acct = new Account("1234567" , 1000);
//模拟两个线程对同一个账户取钱
new DrawThread("甲" , acct , 800).start();
new DrawThread("乙" , acct , 800).start();
}
}[/code]这个例子运行结果之后就得出账户余额最后为负值,
作者:
匿名
时间:
2011-7-24 14:01
synchronized 非静态方法只是保护当前实例
synchronized 静态方法才是包括类所有共享的数据
1.synchronized 方法:通过在方法声明中加入 synchronized关键字来声明 synchronized 方法。如:
public synchronized void accessVal(int newVal);
synchronized 方法控制对类成员变量的访问:每个类实例对应一把锁,每个 synchronized 方法都必须获得调用该方法的类实例的锁方能执行,否则所属线程阻塞,方法一旦执行,就独占该锁,直到从该方法返回时才将锁释放,此后被阻塞的线程方能获得该锁,重新进入可执行状态。这种机制确保了同一时刻对于每一个类实例,其所有声明为 synchronized 的成员函数中至多只有一个处于可执行状态(因为至多只有一个能够获得该类实例对应的锁),从而有效避免了类成员变量的访问冲突(只要所有可能访问类成员变量的方法均被声明为 synchronized)。
在 Java 中,不光是类实例,每一个类也对应一把锁,这样我们也可将类的静态成员函数声明为 synchronized ,以控制其对类的静态成员变量的访问。
synchronized 方法的缺陷:若将一个大的方法声明为synchronized 将会大大影响效率,典型地,若将线程类的方法 run() 声明为 synchronized ,由于在线程的整个生命期内它一直在运行,因此将导致它对本类任何 synchronized 方法的调用都永远不会成功。当然我们可以通过将访问类成员变量的代码放到专门的方法中,将其声明为 synchronized ,并在主方法中调用来解决这一问题,但是 Java 为我们提供了更好的解决办法,那就是 synchronized 块。
2. synchronized 块:通过 synchronized关键字来声明synchronized 块。语法如下:
synchronized(syncObject)
{
//允许访问控制的代码
}
synchronized 块是这样一个代码块,其中的代码必须获得对象 syncObject (如前所述,可以是类实例或类)的锁方能执行,具体机制同前所述。由于可以针对任意代码块,且可任意指定上锁的对象,故灵活性较高。
欢迎光临 黑马程序员技术交流社区 (http://bbs.itheima.com/)
黑马程序员IT技术论坛 X3.2