黑马程序员技术交流社区

标题: 多线程--疑问 [打印本页]

作者: jerry2627    时间: 2012-11-8 17:26
标题: 多线程--疑问
本帖最后由 冯海霞 于 2012-11-9 11:45 编辑

class sFirstThread implements Runnable
{
        private int i;
        //重写run方法 此处就是线程执行体
        public void run()
        {
//当将注释打开后 打印结果会是一个线程先打印完,另一个才打印,和利用同步函数结果不一样
                //synchronized(sFirstThread.class)
                {
                        method();
                }
        }
        public synchronized void method()
        {
                for(; i<1000; i++)
                {
                        System.out.println(Thread.currentThread().getName()+"+"+i);
                }        
        }
}
public class Demo3 {
        public static void main(String[] args)
        {
                int i = 0;
                while(i++<10)
                {
                        System.out.println(Thread.currentThread().getName()+" "+i);
                }
                new Thread(new sFirstThread()).start();
                new Thread(new sFirstThread()).start();
                /**奇迹 两个线程访问的不是共享数据 当使用同步代码块的时候
                 * 能够实现一个线程先打印完,另一个线程才继续打印
                 * 但是使用同步函数就不行了*/
        }
}

作者: 张超    时间: 2012-11-8 18:55
//分析思路:同步函数不能够同步那说明他们用的不是同一把锁,而每个线程有的this这个锁旗标。你创建了两个对象




while(i++<10)
                {
                        System.out.println(Thread.currentThread().getName()+" "+i);
                }
                new Thread(new sFirstThread()).start();//
                new Thread(new sFirstThread()).start();//
/*上面的两行有问题,创建了两个对象。
改正后是:
sFirstThread t=new sFirstThread();
new Thread(t).start();
new thread(t).start();
作者: 李计伟    时间: 2012-11-8 20:39
是不是锁对象有问题 。同步代码块,锁对象是任意对象。同步方法,锁对象是this对象。静态方法。锁对象是当前资源对象的字节码文件对象。需要考虑使用的锁对象是否是同一把。
作者: jerry2627    时间: 2012-11-9 11:42
问题解决
作者: 王振    时间: 2012-11-9 11:51
本帖最后由 王振 于 2012-11-9 11:53 编辑

首先看为什么在method上加同步不能实现你要的结果:
  1. class sFirstThread implements Runnable
  2. {
  3. private int i;
  4. public void run()
  5. {
  6. method();
  7. }

  8. public synchronized void method()
  9. {
  10. for(; i<1000; i++)
  11. {
  12. System.out.println(Thread.currentThread().getName()+"+"+i);
  13. }
  14. }
  15. }
复制代码
1、这里你在run()方法中调用了一个加锁的方法method()。然后在测试类的主方法中启动了两个线程,
      相当于创建了两个线程对象(没有名字,你直接使用了),为了便于解释,这里假设两个线程分别是t1,t2,与之相关的sFirstThread 对象分别为s1,12。
2、对于普通加锁的方法,锁就是this,即调用该方法的对象就是该方法的锁。很明显,2个线程你调用了2次该方法,第一次调用时用到的锁是s1,第二次用到的锁是s2。
     由于它们使用的是不同的锁,因此就相当于是两个完全不相干的线程在执行,谁抢到执行权谁就执行。
因此谁先执行谁后执行是随机的。

然后再来看在run()中加锁为什么能实现一个线程先打印完,另一个线程才开始继续打印
  1. class sFirstThread implements Runnable
  2. {
  3. private int i;
  4. public void run()
  5. {
  6. synchronized(sFirstThread.class){
  7. method();
  8. }
  9. }

  10. public synchronized void method()
  11. {
  12. for(; i<1000; i++)
  13. {
  14. System.out.println(Thread.currentThread().getName()+"+"+i);
  15. }
  16. }
  17. }
复制代码
1、这里你在run()方法中添加了一个同步代码块,锁是sFirstThread.class ,然后将method()方法放到了同步代码块中。
2、你要搞清楚一个问题,程序中为什么要用到同步代码块?是不是想让代码块中的代码作为一个不可分割的整体?要么不执行,只要执行就要全部执行完毕。
3、你把for循环打印的过程放到了同步代码块中,它要么没有得到锁,不执行,要么就是得到锁,执行完毕。
4、又由于两个线程的锁都是sFirstThread.class,因此实现了同步。
备注:method()方法是否加synchronized 效果都一样,这里的同步不是靠它

如果你对上面讲的第2条不太理解什么意思的话,可以看下面的这个例子:
  1. while(true) {
  2. if(count > 0) {
  3. System.out.println("这是" + getName() + ",现在卖出的是第" + (count--) + "张票。");
  4. }
  5. }
复制代码
一开始学多线程一般是举这样的例子,因为不能保证if判断和里面的打印语句作为一个整体执行,所以才提出了同步的概念,
也正是由于加同步代码块,才保证了执行完if判断,肯定会紧接着执行打印语句。
跟这个做对比,把if化成for,不是一个道理吗?





欢迎光临 黑马程序员技术交流社区 (http://bbs.itheima.com/) 黑马程序员IT技术论坛 X3.2