最近开始学习Java多线程,边看书边做笔记,写一点自己的理解。首先抛出问题:Java中的非线程安全问题。
非线程安全问题主要是指:多个线程对同一个对象中的同一个实例变量进行操作时会出现值被更改、值不同步的情况,从而影响程序的执行流程。下面代码为一个非线程安全的简单实例:
public class LoginServletTest
{
public static void main(String args[])
{
ALogin a = new ALogin();
BLogin b = new BLogin();
b.start();
a.start();
}
}
class LoginServlet
{
private static String usernameRef;
private static String passwordRef;
synchronized public static void doPost(String username, String password)
{
try
{
usernameRef = username;
if(username.equals("a"))
{
Thread.sleep(5000);
}
passwordRef = password;
System.out.println("username=" + usernameRef + " password=" + password);
}
catch(InterruptedException e)
{
e.printStackTrace();
}
}
}
class ALogin extends Thread
{
@Override
public void run()
{
LoginServlet.doPost("a", "aa");
}
}
class BLogin extends Thread
{
@Override
public void run()
{
LoginServlet.doPost("b", "bb");
}
}
运行结果如下所示:
username=b password=bb
username=b password=aa
下面我们来分析一下出现这个结果的原因:
- 首先,main方法中创建的线程a启动后,执行run方法,在run方法中调用了LoginServlet类的静态方法doPost,由于此时doPost方法的username参数为“a”,所以a线程在修改LoginServlet类的usernameRef静态变量值为a后会休眠5秒;
- 主线程main在执行a.start()后继续运行,创建了b线程,b线程运行时run方法同样调用了doPost方法,由于doPost方法的username参数不为“a”,所以b线程在修改LoginServlet类的静态变量usernameRef值为b后会继续运行并修改passwordRef的值为bb,然后b线程将结果打印出并结束执行。
- a线程休眠5秒苏醒后,会从Thread.sleep(5000);的下一句继续执行,因此a线程会修改passwordRef的值为aa,但是a线程并没有修改usernameRef的值,此时usernameRef值已经被b线程修改为b,所以最后a线程打印出的结果如上。
这个例子是Java非线程安全中的一个最简单的例子,Java多线程是一个复杂的问题,需要不断深入学习。