Java多线程学习笔记(三)同步和异步
首先是一段代码:
1 public class HasSelfPrivateNum { 2 public void addI(String username){ 3 try { 4 int num=0; 5 if(username.equals("a")){ 6 num=100; 7 System.out.println("a set over! "); 8 Thread.sleep(2000); 9 }else{ 10 num=200; 11 System.out.println("b set over! "); 12 } 13 System.out.println(username+" num="+num); 14 } catch (InterruptedException e) { 15 e.printStackTrace(); 16 } 17 } 18 }
上述代码中的含义是HasSelfPrivateNum对象的A和B的判断
之后有两个线程:
1 public class ThreadA extends Thread { 2 private HasSelfPrivateNum numRef; 3 public ThreadA(HasSelfPrivateNum numRef){ 4 super(); 5 this.numRef=numRef; 6 } 7 8 public void run(){ 9 super.run(); 10 numRef.addI("a"); 11 } 12 }
1 public class ThreadB extends Thread{ 2 private HasSelfPrivateNum numRef; 3 public ThreadB(HasSelfPrivateNum numRef){ 4 super(); 5 this.numRef=numRef; 6 } 7 8 public void run(){ 9 super.run(); 10 numRef.addI("b"); 11 } 12 }
我们可以看出来线程A和线程B中我们创建了HasSelfPrivateNum实例。
运行结果中可以看出来,这个程序不存在非线程安全性问题,为什么呢,因为这个变量是方法内部的,方法内部的变量是私有的特性造成了线程安全,并且这个其本身永远线程安全。接下来吧int num这一行代码放在方法之外我们会看到什么呢?
这时我们会看到线程不安全了,两个对象同时操作了业务中的实例变量,所以发生了线程不安全的问题,原因是没有同步,为了让线程安全我们可以家一个同步锁来解决这个问题:
加了同步锁之后运行就安全了,直到A线程执行完成之后在会执行B线程,如果一个线程没有执行完毕,那么其他线程就无法访问这个线程。和之前那个同步锁的道理是一样的,这就是线程的同步.
以上就是线程同步的道理;
下面是线程的异步:
在刚才的程序上在修改main方法中的代码为:
同时创建两个对象然后再两个线程中运行我们会发现运行结果:
我们现在比较一下两个结果:
和
我们会发现在同步的时候,执行方式为执行A线程直到A线程完全执行完毕之后,再去执行B,原因是因为只有一个Has对象,资源存在竞争关系,当我们使用同步锁的时候就会受到同步机制的影响,当A线程占用了这个对象的资源的时候,其他线程就无法访问这个资源了,直到A执行完毕之后,释放了这个资源,这个时候B线程才有资格去拿到这个线程.我们把这个机制叫做同步.
那个第二个输出方式就和前一个不一样了,这种打印效果就是异步的.两个线程访问了两个不同的对象,这两个不同的对象产生了两个锁,所以一个线程中一个对象的锁并锁不住其他对象,所以就会这样输出.
结论:Java中synhronized关键字锁住的是一个对象,而不是一个方法或者一段代码.
=========================================