线程-同步

 1 import java.util.*;
 2 public class thd implements Runnable
 3 {
 4     Timer timer = new Timer();
 5     public static void main(String args[])
 6     {
 7         thd td=new thd();
 8         Thread t1=new Thread(td);
 9         Thread t2=new Thread(td);
10         t1.setName("t1");
11         t2.setName("t2");
12         t1.start();
13         t2.start();
14     }
15     public void run()
16     {
17         timer.add(Thread.currentThread().getName());
18     }
19 }
20 
21 
22 class Timer
23 {
24     private static int num=0;
25     public void add(String name)
26     {
27         num++;
28         try
29         {
30             Thread.sleep(1);
31         }
32         catch(InterruptedException e)
33         {}
34             System.out.println(name+",你是第 "+num+"个使用timer的线程");
35     }
36 }

 执行结果如下:

  t1,你是第 2个使用timer的线程
  t2,你是第 2个使用timer的线程

     奇怪,为什么结果不是 t1,你是第1一个使用timer的线程呢?

     原因是当第一个线程执行访问timer对象的add方法时,num(data 区域)变成了1,而此时t1线程休眠了,此时t2线程开始执行了,访问的也是同一个timer对象,所以num变成了2,此时线程t1睡醒了,开始打印num=2了,所以结果就成了出现的样子。

  我们如果想要的得到的结果,必须让num++ 和System.out.println(name+",你是第 "+num+"个使用timer的线程")成为一个原子性(不可再分)的执行过程,所以这时候线程同步就诞生了。

  下面是两种办法解决同步问题:

第一种:

 1  public void add(String name)
 2     {
 3         synchronized(this)
 4         {
 5             num++;
 6             try
 7             {
 8                 Thread.sleep(1);
 9             }
10             catch(InterruptedException e)
11             {
12                 
13             }
14             System.out.println(name+",你是第 "+num+"个使用timer的线程");
15         }
16     }

     执行结果:

  t1,你是第 1个使用timer的线程
  t2,你是第 2个使用timer的线程

  synchronized(this){} 在括号中语句被一个线程访问时,不允许另外一个线程访问,这就是锁的机制,正是所谓的互斥锁。

 第二种:

 1 synchronized public void add(String name)
 2     {
 3         num++;
 4         try
 5         {
 6             Thread.sleep(1);
 7         }
 8         catch(InterruptedException e)
 9         {
10             
11         }
12         System.out.println(name+",你是第 "+num+"个使用timer的线程");
13     }

执行结果:

  t1,你是第 1个使用timer的线程
  t2,你是第 2个使用timer的线程

这叫做“在执行该方法过程中锁定当前对象”。

 二.关于 synchronized(重要)

       打个比方:一个object就像一个大房子,大门永远打开。房子里有很多房间(也就是方法)。这些房间有上锁的(synchronized方法)和不上锁之分(普通方法)。房门口放着一把钥匙(key),这把钥匙可以打开所有上锁的房间。另外我把所有想调用该对象方法的线程比喻成想进入这房子某个房间的

  所有的东西就这么多了,下面我们看看这些东西之间如何作用的。在此我们先来明确一下我们的前提条件。该对象至少有一个synchronized方法。一个人想进入某间上了锁的房间,他来到房子门口,看见钥匙在那儿(说明暂时还没有其他人要使用上锁的房间)。于是他走上去拿到了钥匙,并且按照自己的计划使用那些房间。注意一点,他每次使用完一次上锁的房间后会马上把钥匙还回去。即使他要连续使用两间上锁的房间,中间他也要把钥匙还回去,再取回来。因此,普通情况下钥匙的使用原则是:“随用随借,用完即还。”这时其他人可以不受限制的使用那些不上锁的房间,一个人用一间可以,两个人用一间也可以,没限制。但是如果当某个人想要进入上锁的房间,他就要跑到大门口去看看了。有钥匙当然拿了就走,没有的话,就只能等了。要是很多人在等这把钥匙,等钥匙还回来以后,谁会优先得到钥匙?Not guaranteed。象前面例子里那个想连续使用两个上锁房间的家伙,他中间还钥匙的时候如果还有其他人在等钥匙,那么没有任何保证这家伙能再次拿到。

原文地址:https://www.cnblogs.com/mu-tou-man/p/3795328.html