开始学习java编程,遇到到了线程同步的问题。在网上查找资料,根据网上的讲解自己调试代码。有如下心得,写下来和众多正在学习java的同学分享。文中对java同步操作的有些观点尚欠准确,有哪些错误的地方,感谢各位java大牛的批评指正。
代码如下:
public class MultiThreadDemo{
public static void main(String[] args) {
TxtThread tt = new TxtThread();
new Thread(tt).start();
new Thread(tt).start();
new Thread(tt).start();
new Thread(tt).start();
}
}
class TxtThread implements Runnable {
Integer num = 100; // 共100张票,有4个线程共同来进行出售
public void run() {
while(num>0){ --------------------------- 1
synchronized (num) {
try { --------------------------- 2
if(num >0){ --------------------------- 3
System.out.println(Thread.currentThread().getName()
+ "this is " + num--); ----------------------------- 4
}
//Thread.sleep(10);
} catch (Exception e) {
e.getMessage();
}
}
}
}
}
程序解析
1.共有4个线程A,B,C,D同时对记录剩余票数的变量num进行操作。
2.当B线程正在执行时,运行到标记1处时,对当前剩余的票数进行判断;若还有票,获得对num变量访问的锁,进入同步代码段。其他三个线程将会被阻塞在标记1处。(同步代码段并不表示临界区,当某个正在执行同步代码段的线程,也可能被调度器切换出去,让其他的线程占用CPU)
3.判断num的值是否大于0,即是否还有票,注意此次判断很重要,原因下面的解释。
注意
标记3中的if判断很重要,最开始在学习他人的代码时,对在同步代码段中,进行如标记3出的判断觉得很好奇。明明在标记1处进行了判断,当进入同步代码段后,num变量只能被当前线程所访问,那么,num的值一定会大于0了,为什么还要判断了。基于这样的想法,没有进行标记3处的判断,结果程序运行后,num的值出现了0,-1,-2这样三个结果。后来反思后,认为可能是因为,可能是,当进行标记1处的判断后,线程B就可能被调度器给切换出去了(多线程中,当前线程可能在任何地方被切换出去,不能对被切换出去的地点进行任何假设)。注意,此种情况下,线程B还没有获得num的锁。此时,若线程D开始被执行,线程D执行标记1处的判断,然后,在获得num的锁,接着执行同步代码,对num的值进行了修改。在之后的某个时间,线程B又开始被执行了,此时,线程B的执行从标记1之后开始执行,不在进行标记1出的判断了,然后在标记4出,再次对num进行了访问,此次的访问和标记1处的访问不同,两次的num的值不同,标记4中访问的值为线程D访问完的,num可能已经为0或-1了。然后,再不进行判断的情况下,自减后,就会造成num值出现0,-1,-2的现象。