如果说我想要得到单调递减的结果
先来一段小代码:
package MyThread;
public class mythread extends Thread{
private int count=5;
public mythread(String name) {
super();
this.setName(name);
}
@Override
public void run() {
super.run();
while(count>0) {
count--;
System.out.println("根据"+this.currentThread().getName()+"计算可以得到最新的count为:"
+count);
}
}
}
现在在run这个中运行一下:
package test;
import MyThread.mythread;
public class Run {
public static void main(String[] args) {
mythread a=new mythread("A");
mythread b=new mythread("B");
a.start();
b.start();
}
}
运行结果为:
分析:这个结果可以看出来,创立了两个线程,并且每个线程都有“自己的”count变量,并且有自己的count变量的值,这种情况我们就称之为不共享你管你的,我管我的,我的影响不了你,你的也管不了我,并且我不能控制你的你的也不能控制我的
如果说想实现这两个线程共同的对同一个count变量进行减法操作,那么这就是我们的“共享”,共享也就是多个线程可以访问同一个数据的意思,简单看一个案例:
package MyThread;
public class mythread extends Thread{
private int count=5;
@Override
public void run() {
super.run();
count--;
//不要使用for,不然同步了之后其他的线程就没有机会了
//这里可以看出一直就是由一个线程进行减法运算
System.out.println("根据"+this.currentThread().getName()+"计算可以得到最新的count为:"
+count);
}
}
在run里跑一跑:
package test;
import MyThread.mythread;
public class Run {
public static void main(String[] args) {
mythread mythread=new mythread();
Thread a=new Thread(mythread,"A");
Thread b=new Thread(mythread,"B");
Thread c=new Thread(mythread,"C");
Thread d=new Thread(mythread,"D");
Thread e=new Thread(mythread,"E");
a.start();
b.start();
c.start();
d.start();
e.start();
}
}
运行结果:
在这里可以看到就是C和D的结果一致,他们的count值都是1,这就说明了C和D同时对count变量进行了处理,产生了“非线程安全”问题
得不到我们想要的依次递减这样的结果
这就和count- -这个语句有关了
在一些JVM中,对于像- -这样的语句的操作处理分为三步:
1、首先先把原来的那么count值先取
2、计算count-1
3、重现对count赋值
对于这简简单的三个步骤,如果同时间有多个线程同时访问的话,那么必定会出现非线程安全问题
就比如在幼儿园发糖果的时候,每个小朋友必须在前一个小朋友拿了之后才能去拿糖果,这样糖果就不断的进行减一操作,其实也就是“排队”,但是对于线程来说,同时运行的时候,可不一定就是这么“规规矩矩”的了,这个时候就出现了“synchronized”关键字的出现,那么现在我们将上面的代码加上这个关键字,其他不变:
package MyThread;
public class mythread extends Thread{
private int count=5;
@Override
synchronized public void run() {
super.run();
count--;
System.out.println("根据"+this.currentThread().getName()+"计算可以得到最新的count为:"
+count);
}
}
运行结果:
发现可以得到我们想要的结果了
这个关键字这么厉害?!!!
是的就是这么厉害
关键字解释
这个可以理解成在没有加上关键字的时候run方法没有被上锁,就像脱缰的野马,那么这个时候如果上锁,那么就说明其他的线程必须等到当前正在运行run方法的那个线程结束了,才能去执行。(争锁战)
synchronized可以在任意对象以及方法上加锁,加锁的代码我们称之为“互斥区”或者“临界区”
非线程安全
他的意思我想已经很明朗了,就是指在多个线程对同一个对象中的同一个变量进行操作的时候会同时出现被更改、值不同步的情况,进而影响了程序的运行,下面就如何解决“非线程安全”问题举个例子:
这个例子也还蛮常见的,密码注册问题:
package controller;
public class LoginServlet {
private static String usernameRef;
private static String passwordRef;
public static void doPost(String username,String password) {
try {
usernameRef=username;
if(username.equals("a")) {
Thread.sleep(3000);
}
passwordRef=password;
System.out.println("username="+usernameRef+" "+"password="+passwordRef);
}catch(InterruptedException e) {
e.printStackTrace();
}
}
}
两个测试:
package test;
import controller.LoginServlet;
public class Alogin extends Thread{
@Override
public void run() {
LoginServlet.doPost("a", "aa");
}
}
package test;
import controller.LoginServlet;
public class BLogin extends Thread{
@Override
public void run() {
LoginServlet.doPost("b", "bb");
}
}
Run:
package test;
import MyThread.mythread;
public class Run {
public static void main(String[] args) {
Alogin a=new Alogin();
a.start();
BLogin b=new BLogin();
b.start();
}
}
运行结果:
可以看到这个结果,简直…
同样的我们在doPost函数前面加上关键字“synchronized”:
再运行一次: