各位看官,抓紧上车,老司机要接着飙车了。
<!------------------------------我是万恶的分割线----------------------------------->
上回咱们讲到多线程中有个不得不提的关键字---synchronized,不知道各位看官中有没有对这句话表示费解的(没有的话,咱们就委屈一下,假装有),java的关键字有很多,多线程的关键字也不少,那为什么会说synchronized是多线程中不得不提的关键字呢?各位看官不要着急,备好瓜子,且听我细细道来。
话说当年java初现,天地法则新立,各种不足(ps:有不足就对了,没有漏洞的话那还让人活不活了),宇宙间那家伙是一片混乱。因为制度的不完善,导致各种行为得不到约束,java这位新君麾下的多线程,I/O等大将更是桀骜不驯,放纵手下无法无天,,,,啥,你问有多疯狂?据说当初多线程的这个“多”代表2个以上的数时,效率低就不说了,各个线程的数据传输也会极其混乱,我严重怀疑牛头马面就是早期多线程的“杰出作品”。就在这人神共愤的关键时刻,天空一声巨响,synchronized这个小将化好了妆,踏着七彩祥云就登上了历史的舞台。
上回分解时,不知各位看官还有印象没有,我说过synchronized的作用相当于一个督察,在它的监督下,所有的线程,没错,是所有的,都必须按照先后顺序一个个来,,,,啥?你媳妇要生了?你要回去看儿子?那你也得排队,还有,不准有性别歧视,女孩你就不看了?,,,,,啥?你隔壁的二狗的第三只狗一窝生了40只狗,你要去道喜?那你也得排队
不过,规矩是死的,人是活的,不让插队,那多排几队,大家同时进行。啪(ps:脑补一下,惊堂木一声惊堂),正主来了,今天小子就给大家说道说道synchronized的同步方法(敲黑板)。
上回说到线程安全分为“线程安全”和“非线程安全”,我这有一个祖传的传男不传女,传内不传外的秘密,偷偷告诉大家,大家别往外传,“非线程安全”问题存在于“实例变量”中,如果是方法内的私有变量,则不存在“非线程安全”,也就是俗说的业内黑话---“线程安全”了;如果多个线程同时访问1个对象中的实例变量,那就有可能出现“非线程安全”问题,此外,如果多线程访问的对象中如果有多个实例变量,则运行的结果又可能出现交叉的情况,我严重怀疑牛头马面就是这么出来的(ps:纯属逗乐,都别当真哈)。
实例如下(如果巧合,看来成功的路都是一样的,:)):
首先,创建一个HasSelfPrivateNum类
1 public class HasSelfPrivateNum 2 { 3 public void addI(String userName) 4 { 5 try 6 { 7 int num = 0; 8 if(userName.equals("a")) 9 {10 num = 100;11 System.out.println("a set over");12 Thread.sleep(100);13 }14 else15 {16 num = 200;17 System.out.println("b set over");18 }19 System.out.println(userName+" num="+num);20 }21 catch(InterruptedException e)22 {23 e.printStackTrace();24 }25 }26 }
创建一个ThreadA类:
1 public class ThreadA extends Thread 2 { 3 private HasSelfPrivateNum numRef; 4 public ThreadA(HasSelfPrivateNum numRef) 5 { 6 super(); 7 this.numRef=numRef; 8 } 9 public void run()10 {11 super.run();12 numRef.addI("a");13 }14 }
创建一个ThreadB类:
public class ThreadB extends Thread{ private HasSelfPrivateNum numRef; public ThreadB(HasSelfPrivateNum numRef) { super(); this.numRef=numRef; } public void run() { super.run(); numRef.addI("b"); }}
下面是Run类:
1 public class Run 2 { 3 public static void main(String[] args) 4 { 5 HasSelfPrivateNum numRef = new HasSelfPrivateNum(); 6 ThreadA n = new ThreadA(numRef); 7 n.start(); 8 ThreadB m = new ThreadB(numRef); 9 m.start();10 }11 }
好了,咱们跑一下试试:
试验结果很明显,由于没用synchronized,即两个线程访问一个没有同步的方法,出现了”非线程安全“。下面,我们对程序做一个个微整形,在HasSelfPrivateNum类的public void addI(String userName)方法前添加关键字--synchronized,
1 public class HasSelfPrivateNum 2 { 3 synchronized public void addI(String userName) 4 { 5 try 6 { 7 int num = 0; 8 if(userName.equals("a")) 9 {10 num = 100;11 System.out.println("a set over");12 Thread.sleep(100);13 }14 else15 {16 num = 200;17 System.out.println("b set over");18 }19 System.out.println(userName+" num="+num);20 }21 catch(InterruptedException e)22 {23 e.printStackTrace();24 }25 }26 }
我们再跑一次:
这次试验我们可以看出,由于是同步访问,所以结果是先打印a,然后打印出b.
结论:在两个线程访问同一个对象中的同步方法时,一定是线程安全的。
<!---------------------我是万恶的分割线,我又来了------------->
啪,精彩不断,好戏连连,预知后事如何,且听下回分解。
啪,未完待续。
啪,明天见。
原标题:多线程第二弹
关键词:线程