4

我听说,sleep() 将锁定当前同步方法/块但是在这里,当我在线程 1 上调用 sleep() 时,线程 2 能够访问同一个块?谁能解释一下?

主.java

public class Main {     
    public static void main(String args[])
    {
        Thread1 t1 = new Thread1();
        Thread2 t2 = new Thread2();
        System.out.println("going to start t1");
        t1.start();
        System.out.println("going to start t2");
        t2.start();

    }

}

==================================================== ====================

Thread1.java

public class Thread1 extends Thread{

    public void run() { 
        Syncc s1 = new Syncc();
        s1.me("T1:");
    }   

}

==================================================== ====================

线程2.java

public class Thread2 extends Thread{

    public void run() { 
        Syncc s2 = new Syncc();
        s2.me("T2:");
    }   
}

==================================================== ====================

同步.java

public class Syncc{

    public void me(String s){
        synchronized(this){
        for(int i=0; i<=5; i++)
        {
            System.out.println(s+" "+" "+i);
            try {
                Thread.sleep(10000);
            } catch (InterruptedException e) {              
                e.printStackTrace();
            }
        }
    }
}
}

===========================================

输出:

going to start t1
going to start t2
T2:  0
T1:  0
T2:  1
T1:  1
T1:  2
T2:  2
T1:  3
T2:  3
T1:  4
T2:  4
T2:  5
T1:  5

但是根据 sleep() 方法,它不应该解锁当前同步块吗?如果是这样,输出应该是..

开始t1 开始t2

T1:  0
T1:  1
T1:  2
T1:  3
T1:  4
T1:  5
T2:  0
T2:  1
T2:  2
T2:  3
T2:  4
T2:  5

我的意思是在线程 1 执行之后,只有线程 2 应该启动对吗?什么问题?

4

3 回答 3

9

Syncc这是因为您在这里有两个不同的 in play实例。每个线程都有自己的Syncc.

尝试对单个实例执行相同操作。您还可以在静态上下文上同步并尝试。

模拟、修改Thread1Thread2接受Syncc.

public class Thread1 extends Thread {
    private Syncc syncc;

    public Thread1(Syncc syncc) {
        this.syncc = syncc;
    }

    public void run() { 
        this.syncc.me("T1:");
    }   
}

然后您可以这样启动它们:

public static void main(String args[]) {
    Syncc syncc = new Syncc();

    Thread1 t1 = new Thread1(syncc);
    Thread2 t2 = new Thread2(syncc);

    System.out.println("going to start t1");
    t1.start();
    System.out.println("going to start t2");
    t2.start();
}
于 2012-06-08T09:54:18.660 回答
2

睡眠、让步和加入规则

  • 睡眠用于延迟执行一段时间,当线程进入睡眠状态时不会释放任何锁。

  • 睡眠线程保证至少在 sleep() 方法的参数中指定的时间内睡眠(除非它被中断),但不能保证新唤醒的线程何时真正恢复运行。

  • sleep() 方法是一个静态方法,它使当前正在执行的线程的状态休眠。一个线程不能告诉另一个线程休眠。

  • setPriority() 方法用于 Thread 对象,以赋予线程介于 1(低)和 10(高)之间的优先级,尽管不能保证优先级,并且并非所有 JVM 都识别 10 个不同的优先级 - 某些级别可能被视为有效平等的。

  • 如果未明确设置,线程的优先级将与创建它的线程的优先级具有相同的优先级。

  • 如果有相同优先级的可运行线程,yield() 方法可能会导致正在运行的线程退出。不能保证会发生这种情况,也不能保证当线程退出时会选择另一个线程来运行。线程可能会屈服,然后立即重新进入运行状态。

  • 最接近保证的是,在任何给定时间,当线程运行时,它的优先级通常不会低于处于可运行状态的任何线程。如果高优先级线程进入runnable时低优先级线程正在运行,JVM通常会抢占正在运行的低优先级线程,将高优先级线程放入。

  • 当一个线程调用另一个线程的 join() 方法时,当前运行的线程会一直等待,直到它加入的线程完成。将 join() 方法想象为:“嘿,线程,我想加入到你的末尾。完成后告诉我,这样我就可以进入可运行状态。”

http://www.amazon.com/SCJP-Certified-Programmer-Java-310-065/dp/0071591060

于 2012-06-08T09:58:56.323 回答
0

您已经创建了两个同步对象,每个对象对应一个线程。每个对象都有自己的我的副本。因此,当您启动每个线程时,线程使用 run 方法调用它自己的函数 me 副本。由于这两个线程仅作用于它们的副本,因此这就像单线程场景一样工作。如果您确实想测试多线程场景,则将方法设为静态(类级别方法)并应用类级别锁定。

Thread1.java

public class Thread1 extends Thread{

public void run() { 
    Syncc.me("T1:");
}   

}

线程2.java

public class Thread2 extends Thread{

public void run() { 
    Syncc.me("T2:");
}   

}

同步.java

public class Syncc{

public static void me(String s){
    synchronized(Syncc.class){
    for(int i=0; i<=5; i++)
    {
        System.out.println(s+" "+" "+i);
        try {
            Thread.sleep(10000);
        } catch (InterruptedException e) {              
            e.printStackTrace();
        }
    }
}

} }

于 2012-06-08T10:11:44.540 回答