我正在阅读并试图了解线程中的等待和通知机制。 为此,我需要清除我的概念,因此,只是确定我的概念,我在尝试的例子上提出问题,如下所示
请按照代码段
进行操作class CodeOne implements Runnable{
@Override
public void run(){
try{
synchronized(this){
for(int i=1;i<=5;i++){
System.out.println(Thread.currentThread().getName()+" : "+i);
Thread.sleep(500);
}
}
}catch(Exception e){
e.printStackTrace();
}
}
}
public class ThreadPractiseOne{
public static void testOne() throws Exception{
CodeOne code = new CodeOne();
Thread t1 = new Thread(code,"THREAD-ONE");
Thread t2 = new Thread(code,"THREAD-TWO");
t1.start();
t2.start();
}
public static void main(String[] args){
try{
testOne();
}catch(Exception e){
}
}
}
从上面的代码我们可以看到sunchronized块使用'this'作为参数。 它的目的是,在main方法中创建的线程获取对象CodeOne的锁定,因此只有一个线程能够访问它。
我的上述理解是否正确?
如果是,
比我想根据下面编写的代码再问一个问题,
public class MyThread extends Thread{
public MyThread(String name){
this.setName(name);
}
public int total;
@Override
public void run(){
try{
synchronized(this){
System.out.print(" ");
for(int num=1; num <= 3; num++){
total += num;
System.out.print("..");
Thread.sleep(1000);
}
System.out.println("\n");
notify();
}
}catch(Exception e){
e.printStackTrace();
}
}
}
public class MainThread {
public static void main(String [] args){
MyThread t1 = new MyThread("ONE");
try{
t1.start();
synchronized(t1){
System.out.println(" Waiting for Thread ONE to complete ");
t1.wait();
}
System.out.println(" TOTAL is "+t1.total);
}catch(Exception e){
e.printStackTrace();
}
}
}
从上面的代码我们可以在类MainThread
的main方法中看到,我使用了synchronized块但是参数传递了i t1,即线程实例。
这是否意味着主线程获取't1'上的锁?
如果是,为什么?
如果我这样做
synchronized(new MainThread())
在MainThread
课程中,我得到了一个例外
java.lang.IllegalMonitorStateException
为什么?
顺便说一下第二个程序的输出
Waiting for Thread ONE to complete
......
TOTAL is 6
答案 0 :(得分:1)
从上面的代码我们可以看到synchronized块使用'this'作为 论点。它的目的是,在主要创建的线程 方法获取对象CodeOne的锁定,因此只有一个线程 能够访问它。
一次只有一个线程能够访问在该对象上同步的synchronized
块内的代码。
这是否意味着主线程获取't1'上的锁?
在此示例中,this
和t1
碰巧引用了相同的MyThread
对象。
在MainThread类中,我得到一个异常
您必须向我们展示实际导致此问题的代码,但您无法在尚未notify
开启的对象上调用wait
或synchronized
。
顺便说一下第二个程序的输出
这取决于竞争条件。这取决于Thread
首先获取MyThread
对象上的锁定。如果它是主线程,那么这就是你将获得的输出。如果它是另一个线程,那些线将被反转。
我在wait()
和notify()
上没有看到任何问题,所以我只想提及已经作出一般性解释的Gray's answer。
最后,不要在synchronized
个对象上Thread
。当他们所指的实际线程结束时,它们的行为与普通对象不同。
答案 1 :(得分:1)
在main方法中创建的线程获取对象CodeOne的锁定,因此只有一个线程能够访问它。
是的,这是正确的。认识到它们锁定CodeOne
的相同实例非常重要。只有在同一对象实例上有多个线程为synchronized
时,锁才有效。
这是否意味着主线程获取't1'上的锁?
是。主线程和分叉线程都锁定在同一个Thread
实例上。另外,将您的课程定义为implements Runnable
而不是扩展Thread
被认为是更好的模式。例如,Thread
代码的其他部分锁定在Thread
实例上。因为你锁定它也可能会导致一些意想不到的后果。
同样重要的是要意识到只是调用notify();
是一种糟糕的模式。你应该明确地说this.notify();
。他们做同样的事情,但它应该在synchronized (this) { ... this.notify(); }
之间具有平价。
这是否意味着主线程获取't1'上的锁?
是。主线程锁定t1
并且在this
锁定的线程内部。所以他们锁定在同一个对象实例上。我不知道如何回答“为什么”这个问题。
java.lang.IllegalMonitorStateException
如果您尝试wait()
或notify()
而不在synchronized
区域内,则会发生这种情况。如果您说:
synchronized(new MainThread()) {
...
notify();
}
然后,您正在同步一个对象,并尝试在不同的对象上通知您尚未锁定。锁对象通常应该是由多个线程共享的private final
对象实例。做synchronized (new ...)
之类的事情实际上从来都不是一个好模式。