非线程安全主要是指多个线程对同一个对象中的同一个实例变量进行操作时会出现值被更改、值不同步的情况,进而影响程序的执行流程。
比如两个账号同时登陆的情况:
例子说明:
一个非线程安全环境:
package com.zxc.thread.test;
public class LoginTest {
private static String usernameRef;
private static String passwordRef;
public static void doPost(String username,String password){
usernameRef = username;
try {
if(username.equals("a")){
Thread.sleep(5000);
}
passwordRef = password;
System.out.println("username=" + usernameRef + " password=" + passwordRef);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
线程ALogin.java代码如下:
package com.zxc.thread.test;
public class ALogin extends Thread{
@Override
public void run(){
LoginTest.doPost("a", "aa");
}
}
线程BLogin.java代码如下:
package com.zxc.thread.test;
public class BLogin extends Thread {
@Override
public void run(){
LoginTest.doPost("b", "bb");
}
}
运行类Run.java代码如下:
package com.zxc.thread.test;
public class Run {
public static void main(String[] args) {
ALogin a = new ALogin();
a.start();
BLogin b = new BLogin();
b.start();
}
}
运行结果:
username=b password=bb
username=b password=aa
这个就是非线程安全的体现,要解决这个问题,可以使用synchronizsd关键字,synchronized可以在任意对象及方法上加锁,而加锁的这段代码成为“互斥区”或“临界区”,当一个线程想要执行同步方法里面的代码时,线程首先尝试去拿这把锁,如果能够拿到这把锁,那么这个线程就可以执行synchronized里面的代码,如果拿不到,这个线程就会不断地尝试拿这把锁,直到能够拿到为止,而且是有多个线程同时去争抢这把锁。
修改LoginTest.java代码:
public class LoginTest {
private static String usernameRef;
private static String passwordRef;
synchronized public static void doPost(String username,String password){
usernameRef = username;
try {
if(username.equals("a")){
Thread.sleep(5000);
}
passwordRef = password;
System.out.println("username=" + usernameRef + " password=" + passwordRef);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
运行结果:
username=a password=aa
username=b password=bb