线程的安全,在线程的安全性问题中synchronized关键字很重要,本篇文章主要讲解一下synchronized在线程锁中的简单应用.(注意:只有在对数据进行修改,写,线程才会不安全,如果只是对数据的查询,则效率优先,不加synchronized)
先来看下面一段代码
package com.qftest;
/**
* 在线取钱系统
*
* @author 24526
*
*/
public class Demo1 {
public static void main(String[] args) {
quqian acc = new quqian(10010, "123456", 2000d);
husband hu = new husband(acc);
wife wi = new wife(acc);
new Thread(hu).start();
new Thread(wi).start();
}
}
class husband implements Runnable {
quqian acc;
husband hu;
public husband(quqian acc) {
this.acc = acc;
}
@Override
public void run() {
this.acc.qu(10010, "123456", 200);
}
}
class wife implements Runnable {
quqian acc;
wife wi;
public wife(quqian acc) {
this.acc = acc;
}
@Override
public void run() {
this.acc.qu(10010, "123456", 4400);
}
}
class quqian {
int id;
String pwd;
double money;
double blance;
public quqian(int id, String pwd, double blance) {
this.id = id;
this.pwd = pwd;
this.blance = blance;
}
public void qu(int id, String pwd, double money) {
if (id == this.id && pwd.equals(this.pwd)) {
System.out.println("密码输入正确,请稍后...");
if (blance > money) {
blance -= money;
System.out.println("您当前可用余额为:" + blance);
} else {
System.out.println("可用余额不足!!");
}
} else {
System.out.println("密码或账号输入错误,请重新输入...");
}
}
}
结果为:
密码输入正确,请稍后...
可用余额不足!!
密码输入正确,请稍后...
您当前可用余额为:1800.0
上述代码展示了一个经典的取钱案列,在该代码中出现了线程不安全的情况.
在这种情况下,线程锁synchronized应运而生.
使用方法:
synchronized(临界资源对象){
代码(原子操作)
}
下面是加上了synchronized的代码(部分)
class husband implements Runnable {
quqian acc;
husband hu;
public husband(quqian acc) {
this.acc = acc;
}
@Override
public void run() {
synchronized (acc) {
this.acc.qu(10010, "123456", 8800);
}
}
}
class wife implements Runnable {
quqian acc;
wife wi;
public wife(quqian acc) {
this.acc = acc;
}
@Override
public void run() {
synchronized (acc) {
this.acc.qu(10010, "123456", 400);
}
}
}
结果:
密码输入正确,请稍后...
可用余额不足!!
密码输入正确,请稍后...
您当前可用余额为:1600.0
需要注意的是,在使用synchronized的时候资源一定要锁对,如果直接锁方法的话,很可能直接锁住了整个类的对象,所以建议使用synchronized同步块
synchronized(临界资源对象){
代码(原子操作)
}
下
来简单介绍一下各种块
1)方法中的块(局部块):用来解决变量的作用域,在该块中定义的变量出了这个块就用不了
2)类中的块:就是在成员属性的位置放置的代码块,称为构造代码块(在方法外部),与构造方法的作用类似(初始化对象信息).如果是static,则叫静态代码块,与方法代码块不同的是,它是随着类的加载而加载,在方法之前加载.
3)同步块,(也是在方法里面),上面讲了,现在来总结一下
a)上面语法中的临界资源对象可以是任何对象,但是一般推荐使用共享资源.
b)同步方法中无需指定同步监视器,因为同步方法中的同步监视器是this即该对象本身,或者class只是类的模子