黑马程序员技术交流社区

标题: 线程同步 [打印本页]

作者: 李元峰    时间: 2012-6-20 20:16
标题: 线程同步
本帖最后由 李元峰 于 2012-6-20 22:16 编辑

本来我是要预期得到这样的结果的:
main() count=200
count=100
当时程序执行后 得到这样结果:
main() count=100
count=100
两个方法都是同步的,
下面是代码,请大侠分析下程序执行的路径
  1. package javatext;

  2. public class Demo{
  3.         public static int count = 0;
  4.         public static synchronized void method1(){
  5.                 count=100;
  6.                 try {
  7.                         Thread.sleep(3000);
  8.                 } catch (InterruptedException e) {
  9.                         e.printStackTrace();
  10.                 }
  11.                 System.out.println("count="+count);
  12.         }
  13.         
  14.         //public static void method2(){
  15.         public static synchronized void method2(){
  16.                 count=200;
  17.                 try {
  18.                         Thread.sleep(1000);
  19.                 } catch (InterruptedException e) {
  20.                         e.printStackTrace();
  21.                 }
  22.                
  23.         }

  24.         
  25.         public static void main(String[] args){
  26.                 Thread myThread = new Thread(new MyRunnable());
  27.                 myThread.start();
  28.                
  29.                
  30.                 Demo.method2();
  31.                 System.out.println("main() count="+count);
  32.                 //如果后调用的是method2() 则打印出的是 main() count=200
  33.                 //说明先执行了method2()方法,主线程休眠之后执行了 method1()方法,使count=100 MyThread线程休眠三秒,主线程
  34.                 //执行,打印main() count=100,然后3秒后执行MyThread 打印count=100
  35.                
  36.                  
  37.         }
  38. }

  39. class MyRunnable implements Runnable{
  40.         public void run(){
  41.                 Demo.method1();
  42.         }
  43. }
复制代码

作者: 耿鑫    时间: 2012-6-20 20:25
本帖最后由 耿鑫 于 2012-6-20 20:28 编辑

楼主的执行结果是正确的,首先先明确synchronized锁的是谁,你就明白了。
如果某个synchronized方法时static的,那么当线程访问该方法时,它锁的并不是synchronized方法所在的对象,而是synchronized方法所在的对象所对应的Class对象因为java中无论一个类有多少个对象,这些对象会对应唯一一个Class对象,因此当线程分别访问同一个类的两个static,synchronized方法时,他们的执行顺序也是顺序的,也就是说一个线程先去执行方法,执行完毕后另一个线程才开始执行。
作者: 龙秋地    时间: 2012-6-20 20:55
本帖最后由 龙秋地 于 2012-6-20 21:02 编辑

楼主我刚开始也没弄明白是怎么回事但是我在两个地方加了一下System.out.println(count);
我貌似明白了主函数的运行顺序.
第一个是在method2()方法里count=200;下面加的.
第二个是在主函数最后加的.具体代码你可以自己试试.


  1. public class Demo{
  2.         public static int count = 0;
  3.         public static synchronized void method1(){
  4.                 count=100;
  5.                 try {
  6.                         Thread.sleep(3000);
  7.                 } catch (InterruptedException e) {
  8.                         e.printStackTrace();
  9.                 }
  10.                 System.out.println("count="+count);
  11.         }
  12.         
  13.         //public static void method2(){
  14.         public static synchronized void method2(){
  15.                 count=200;
  16.                                 System.out.println(count);
  17.                 try {
  18.                         Thread.sleep(1000);
  19.                 } catch (InterruptedException e) {
  20.                         e.printStackTrace();
  21.                 }
  22.                
  23.         }

  24.         
  25.         public static void main(String[] args){
  26.                 Thread myThread = new Thread(new MyRunnable());
  27.                 myThread.start();
  28.                
  29.                
  30.                 Demo.method2();
  31.                 System.out.println("main() count="+count);
  32.                 //如果后调用的是method2() 则打印出的是 main() count=200
  33.                 //说明先执行了method2()方法,主线程休眠之后执行了 method1()方法,使count=100 MyThread线程休眠三秒,主线程
  34.                 //执行,打印main() count=100,然后3秒后执行MyThread 打印count=100
  35.                
  36.                                 System.out.println(count);
  37.                  
  38.         }
  39. }

  40. class MyRunnable implements Runnable{
  41.         public void run(){
  42.                 Demo.method1();
  43.         }
  44. }
复制代码
运行结果是这个
这就说明在主函数运行时,开启线程语句和Demo.method2()应该是是在method1()之前运行的,
我已经反复试验多次,每次都是先打印出200,也许这就是多线程的作用.主函数是一个线程你自己
又建立了一个线程,这个都是同时在执行的,但是你的线程由于休眠,所以当主函数已经运行三个除了
你自己建立的线程以外,还等了三秒才输出count=100的.

运行结果.png (850 Bytes, 下载次数: 73)

运行结果.png

作者: 李元峰    时间: 2012-6-20 21:25
龙秋地 发表于 2012-6-20 20:55
楼主我刚开始也没弄明白是怎么回事但是我在两个地方加了一下System.out.println(count);
我貌似明白了主函 ...

我仔细分析了下原来程序时这样执行的,程序先执行的是主线程的method2() 把count设成了200没错,确实这样,我debug 了一下是这样的,并且myThread线程已经锁住了method1()和methos2()方法,所以即使myThread 睡眠了1秒,主线程依然无法执行method1()方法,当myThread线程醒来时,他并不是立即去执行System.out.println("main() count="+count);如果是这样的话,那结果就是

Main() count=200了,说明程序这时执行了主线程的method1(),这样b又被设为100,当前线程睡眠3秒,这时候才来执行

System.out.println("main() count="+count),3秒后主线程醒来,执行

System.out.println("count="+count);

这样打印的结果就为:

main() count=100

count=100

当我把System.out.println("main() count="+count); 这句放在method2()方法里时理所当然的程序结果就为:

main() count=200

count=100
作者: 龙秋地    时间: 2012-6-20 21:48
李元峰 发表于 2012-6-20 21:25
我仔细分析了下原来程序时这样执行的,程序先执行的是主线程的method2() 把count设成了200没错,确实这样 ...

我已经完全迷糊了,我想知道的是myThread()线程是怎么锁住两个method()方法的.
过程能详细说明一下不?是不是锁住的意思是就是睡眠了.
怎么线程醒来后就解锁了吗?就可以执行method1()方法了?
怎么解的锁?
作者: 李元峰    时间: 2012-6-20 21:56
龙秋地 发表于 2012-6-20 21:48
我已经完全迷糊了,我想知道的是myThread()线程是怎么锁住两个method()方法的.
过程能详细说明一下不?是不 ...

是这样的,如果都是同步的方法,只要有一个线程进入了一个同步方法,那么这个对象的所有同步的方法都会被当前线程锁定,当其他线程再来访问这个对象的同步方法时,他也想锁定该对象的所有的同步方法,当时发现他的所有的同步方法已经被别的线程锁住了,只有当之前的那个线程访问完之后,就交出锁,这样,后来的那个线程才能再去锁定这个对象的同步方法
作者: 龙秋地    时间: 2012-6-20 22:01
李元峰 发表于 2012-6-20 21:56
是这样的,如果都是同步的方法,只要有一个线程进入了一个同步方法,那么这个对象的所有同步的方法都会被 ...

恩 明白了.
谢谢.
:L太不好意思了 明明是你问题,结果变成我问你回答了.
作者: 山水游客    时间: 2012-6-20 23:06
静态的同步方法,使用的锁是该方法所在类的字节码文件对象。 类名.class,Demo类有两个静态同步方法,那么其中的一个方法被调用时,Demo.class对象的锁被锁住。因此,没有其他线程可以条用统一各类的其他的的同步静态方法。
我调试了一下,得到的结果是:
main() count=100
count=100
我感觉原因是你只启动了Demo.method1()的线程,而没有启动Demo.method2()的线程。所以method2()不会和method1()形成 同步竞争,如果想实现你想要的答案
,可以把method2()加到run方法里。

作者: 李元峰    时间: 2012-6-20 23:19
孙胜录 发表于 2012-6-20 23:06
静态的同步方法,使用的锁是该方法所在类的字节码文件对象。 类名.class,Demo类有两个静态同步方法,那么其 ...

有竞争的,你可以到 分别到method1() 和method2() 方法里面去打印信息,看看有没有竞争




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