编写一个线程类,让他访问同一对象的静态资源,实现线程访问的同步
请看下面的代码:public class Test_Sync extends Thread {
  Timer timer = new Timer(); //将Timer类设计成Test_Sync类的属性
  //重写run()方法
  public void run(){
   //Thread.currentThread().getName()得到正在执行线程的名字
    timer.add(Thread.currentThread().getName());//调用timer的add(String name)方法
  }
  
  public static void main(String[] args) {
    Test_Sync t1 = new Test_Sync(); //得到线程Test_Sync的实例t1
    Test_Sync t2 = new Test_Sync(); //得到线程Test_Sync的实例t2
    t1.setName("t1");  //设置线程的名字
    t2.setName("t2");
    t1.start(); //启动线程
    t2.start();
  }
  
} class Timer{
  private static int num = 0; //设置共享资源,请注意它的属性是static
  
  //该方法被声明为synchronized
  public synchronized void add(String name){ 
    num ++; //每调用一次该方法num加1
    try {
     Thread.sleep(1); //线程休眠1ms
    }catch(InterruptedException e){
     e.printStackTrace();
    }
    System.out.println(name+", 你是第"+num+"个访问timer的线程");
  }
}这是上面代码的执行结果:

t1, 你是第2个访问timer的线程
t2, 你是第2个访问timer的线程

显然这个结果是错误的:如果将上面的代码作如下修改:public class Test_Sync implements Runnable{
public Timer t = new Timer();
public void run(){
t.add(Thread.currentThread().getName());
}

public static void main(String[] args){
Test_Sync ts1 = new Test_Sync();
Thread t1 = new Thread(ts1);
Thread t2 = new Thread(ts1);
t1.start();
t2.start();
}
}得到正确的结果应该是:
t1, 你是第1个访问timer的线程
t2, 你是第2个访问timer的线程
为什么,在第一中的实现方式中add(String name)已被声明为Synchronzied,但是很明显他并没有锁住timer对象,而如果让这个线程类实现Runnable接口而不是继承Thread,则所需的功能就可以实现。所以这个问题引发了我的思考,如果要实现线程同步,对于extends Thread 和 implements Runnable,那个更好?如果两个都可以,那他们分别使用于那些情况?

解决方案 »

  1.   

    两都可以, 如果有多继承的时候  实现在接口的好, 还可以继承别的类。区别主要是继承了 Thread  不能在继承别的类了,而实现Runnable接口,还可以继承别的类和实现别的别的接口,用的时候 看具体情况
      

  2.   

    因为第一种方法你new了两个继承了thread的类,而第二种只new了一个,只不过另外new了2个Thread你可以把第一种方法改成如下试试
          public static void main(String[] args) {
            Test_Sync t1 = new Test_Sync();    //得到线程Test_Sync的实例t1
            new Thread(t1,"t1").start();
            new Thread(t1,"t2").start();
            //得到线程Test_Sync的实例t2
    //        t1.setName("t1");     //设置线程的名字
    //        t2.setName("t2");
    //        t1.start();    //启动线程
    //        t2.start();
          }
      

  3.   

          public static void main(String[] args) {
            Test_Sync t1 = new Test_Sync();    //得到线程Test_Sync的实例t1
            new Thread(t1,"t1").start();
            new Thread(t1,"t2").start();
            //得到线程Test_Sync的实例t2
    //        t1.setName("t1");     //设置线程的名字
    //        t2.setName("t2");
    //        t1.start();    //启动线程
    //        t2.start();
          }
    作如上修改确实实现了线程同步,但我想问您"new Thread(t1,"t2").start();"中t1实际是继承Thread,而非实现Runnable,这和API中new Thread(Runnable target, String name)不同,而编译通过,这是为什么? 谢谢!
      

  4.   

    用第一种方法,修改Timer类一下
    class Timer {
        private static int num = 0;    //设置共享资源,请注意它的属性是static    //该方法被声明为synchronized
        public synchronized void add(String name) {
            System.out.println("执行  add  方法");    //加上开始调用方法打印
            num++;    //每调用一次该方法num加1
            try {
                Thread.sleep(1000);    //线程休眠1ms     sleep改成1秒
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println(name + ", 你是第" + num + "个访问timer的线程");
        }
    }在运行第一种方法,
    结果:
    执行  add  方法
    执行  add  方法
    t1, 你是第2个访问timer的线程
    t2, 你是第2个访问timer的线程指所以会这样是因为你有2个Test_Sync类的对象,而每个对象里面又分别new timer()一个新的对象,而synchronized方法对于两个不同对象是不能同步的第二次你的运行结果是正确的,因为你只有一个Test_Sync对象,对于timer对象也只有一个,这样synchronized方法是可以同步的,出现的结果就是你想要的
      

  5.   

    无论是用Thread还是Runnable都没问题,关键看你new了几个timer对象了
      

  6.   


    class Thread implements Runnable
      

  7.   

    看看Thread的源代码
    public class Thread implements Runnable {