线程安全
1.同步代码块
线程安全:《Java 并发实践》多个线程,访问一个类的对象,如果不考虑这些线程在运行环境下的调度和交替执行,并且不需要额外同步和调用方法,也不需要额外的代码块的协调,那么这个类仍是正确的。那么这个类就是线程安全的类。
实例:
public class SafeThread{
public static void main(String[] args) {
new SafeThread().safeThreadTest();
}
PrintString ps = new PrintString();
public void safeThreadTest() {
new Thread(new Runnable() {
@Override
public void run() {
while(true) {
ps.showString("AAAAAAAAAAAAA");
}
}
}).start();
new Thread(new Runnable() {
@Override
public void run() {
while(true) {
ps.showString("BBBBBBBBBBBB");
}
}
}).start();
}
}
class PrintString{
//synchronized是一把锁,一次只允许一个线程进入方法体内
public synchronized void showString(String str) {
for(int i=0;i<str.length();i++) {
System.out.print(str.charAt(i));
}
System.out.println();
}
}
class PrintString{
public void showString(String str) {
//第二种方式:锁住要执行的代码
//锁住类的字节码PrintString.class或者this当前对象或str.getclass()
synchronized(this) {
for(int i=0;i<str.length();i++) {
System.out.print(str.charAt(i));
}
System.out.println();
}
}
}
同步代码块:就是定义了一组原子性的操作,所谓原子性的操作,就是说只允许一个线程进入。直到这个线程运行完毕,下一个线程才能进入。
下面我们来看另一个实例:
同时开启两个线程,每个线程自加到10000,两个线程求和。(应该为两万)
public class SafeThread2 {
public int i=0;
AddTest at = new AddTest();
public static void main(String[] args) {
new SafeThread2().threadTest();
}
//线程二自加一万
public void threadTest() {
new Thread(new Runnable() {
@Override
public void run() {
for(int i=0;i<10000;i++) {
at.add();
}
}
}).start();
//线程二自加一万
new Thread(new Runnable() {
@Override
public void run() {
for(int i=0;i<10000;i++) {
at.add();
}
}
}).start();
//等待上方线程结束
//如果上方两个线程没有执行结束,会一直阻塞
//得到当前线程活跃的数量:新建线程一线程二,主线程
while(Thread.activeCount()!=1) {
}
System.out.println(i);
}
class AddTest{
public synchronized void add() {
i++;
}
}
}
下面还有一个ATM取钱的实例:
public class ATM extends Thread{
private String name;
private int money;
private Account account;
public ATM(String name, int money, Account account) {
super();
this.name = name;
this.money = money;
this.account = account;
}
@Override
public void run() {
synchronized (account) {
if(money<account.getBalance()) {
try {
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
//设置账户的余额
account.setBalance(account.getBalance()-money);
//检测账户的余额
System.out.println("账户的余额为:"+account.getBalance());
}else {
System.out.println("账户余额不足...");
}
}
}
public static void main(String[] args) {
Account a=new Account("888888",6000);
new ATM("张三", 5000, a).start();
new ATM("李四", 5000, a).start();
}
}