首先是一段代码:
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关键字锁住的是一个对象,而不是一个方法或者一段代码.
=========================================