你的位置:首页 > Java教程

[Java教程]多线程第二弹


  各位看官,抓紧上车,老司机要接着飙车了。

     <!------------------------------我是万恶的分割线----------------------------------->

  上回咱们讲到多线程中有个不得不提的关键字---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.

结论:在两个线程访问同一个对象中的同步方法时,一定是线程安全的。

<!---------------------我是万恶的分割线,我又来了------------->

啪,精彩不断,好戏连连,预知后事如何,且听下回分解。

啪,未完待续。

啪,明天见。