多线程访问同一资源数据时,容易出现线程安全问题。对银行账户存储钱来说,多线程的并发访问可能会导致问题发生,造成账户资金的损失。而线程同步能够保证某个资源在某一时刻只能被一个线程访问,保证了共享数据的一致性。
线程同步通常采用同步代码块,同步方法,同步锁三种方式实现。
同步代码块
通过同步块实现同步功能
public void run(){
synchronized(this.account){
double d=this.account.getBalance();
if(money<0&&d<-money){
System.out.println(this.getName()+"操作失败,余额不足!");
return;
}else{
d+=money;
System.out.println(this.getName()+"操作成功,目前账户余额为:"+d);
try{
Thread.sleep(1);
}catch(InterruptedException e){
e.printStackTrace();
}
this.account.setBanlance(d);
}
}
}
其中synchronized为同步关键字,this.account为该代码的同步监视器,在这个线程执行同步代码前,要对同步监视器锁定。从而避免了多线程的并发访问。
同步方法
同步方法是通过synchronized关键字修饰需要同步的方法
public synchronized void access(double money){
if(money<0&&d<-money){
System.out.println(this.getName()+"操作失败,余额不足!");
return;
}else{
d+=money;
System.out.println(this.getName()+"操作成功,目前账户余额为:"+d);
try{
Thread.sleep(1);
}catch(InterruptedException e){
e.printStackTrace();
}
}
}
当线程进入一个实例的任何同步方法后,其他线程则不能再进入该实例的所有同步方法,但是非同步方法能被调用。
同步锁
该方法通过ReentrantLock类实现对对象的加锁以及释放锁来控制线程对资源的访问。
public void access(double money){
lock.lock();
try{
if(money<0&&d<-money){
System.out.println(this.getName()+"操作失败,余额不足!");
return;
}else{
d+=money;
System.out.println(this.getName()+"操作成功,目前账户余额为:"+d);
try{
Thread.sleep(1);
}catch(InterruptedException e){
e.printStackTrace();
}
}
}finally{
lock.unlock();
}
}
该方法需要定义锁对象,再将加锁和释放锁根据需要放入方法中
定义锁
private final ReentrantLock lock=new ReentrantLock();
线程在多任务处理应用程序中起着至关重要的作用,单线程的处理方式对于某些程序功能会有些缺陷,而多线程同时有多个线程并发执行,同时完成多个任务,提高了程序的效率,线程同步则是解决了多线程并发时可能发生的一些问题,使多线程能够更好,更安全的给我们的生活带来便利。