1.非线程安全:主要是指多个线程对同一个对象中的同一个实例变量进行操作时会出现值被更改,值不同步的情况,进而影响程序的执行流程。
2.通过在run方法前加入synchronized关键字,使多个线程在执行run方法时,以排队的方式进行处理。当一个线程调用run方法前,先判断run方法有没有被上锁,如果上锁,则说明有其他线程正在调用run方法,必须等待其他线程调用结束后才可以执行run方法。
3.synchronized可以在任意对象及任意方法上加锁,这段代码称为“互斥区”或“临界区”
4.当一个线程想要执行同步方法里的代码时,线程首先尝试去拿这把锁,拿得到,就执行,拿不到,就不断的尝试拿,直到拿到为止,而且是多个线程同时去抢这把锁。
举个例子:两个线程同时访问username和password两个变量。
对username和password赋值的操作,login.java
package test.first;
public class login {
//为全局变量,确保两条线程访问同一资源
private static String usernameRef;
private static String passwordRef;
public static void post(String username, String password) {
try {
usernameRef = username;
//System.out.println(Thread.currentThread().getName());//获取线程名,用于调试
if (username.equals("a")) {//如果username等于a,那么要有一些处理,比如休眠5s
Thread.sleep(5000);
}
//System.out.println(Thread.currentThread().getName());//获取线程名,用于调试
passwordRef = password;
System.out.println("username="+usernameRef+" password="+passwordRef);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
线程一:alogin.java
package test.first;
/*
* 线程a
* */
public class alogin extends Thread{
public void run(){
login.post("a", "aa");
}
}
线程二:blogin.java
package test.first;
/*
* 线程b
* */
public class blogin extends Thread{
public void run(){
login.post("b", "bb");
}
}
主函数:run.java
package test.first;
public class run {
public static void main(String[] args) {
// TODO Auto-generated method stub
alogin a = new alogin();
a.start();
blogin b = new blogin();
b.start();
//匿名内部类写法
//new alogin().start();
//new blogin().start();
}
}
结果:
username=b password=bb
username=b password=aa
原因是:
a运行了-->username=a
a休眠5s-->username=a
b运行了-->username=b
-->password=bb,输出 username = b password = bb
5s之后-->password = aa,输出 username = b password = aa
重点是:username和password是全局变量!!!
解决:在post方法前加synchronized就可以了。