我有以下代码。我希望一个线程完全执行其synchronized方法,然后允许另一个线程访问相同的方法。但事实并非如此。
public class Threads {
/**
* @param args
*/
public static void main(String[] args) {
//Thread Th = new Threads();
Thread th = new Thread (new thread1 ());
th.start();
Thread th1 = new Thread (new thread1 ());
th1.start();
}
}
class thread1 implements Runnable{
String name = "vimal";
public void run() {
System.out.println("Runnable "+this.name);
setNAme("Manish");
}
public synchronized void setNAme(String name){
try {
System.out.println("Thread "+Thread.currentThread().getName());
wait(1000);
this.name = name;
System.out.println("Name "+this.name);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
我有一个输出
Runnable vimal
Thread Thread-0
Runnable vimal
Thread Thread-1
Name Manish
Name Manish
在这里使用synchronized有什么用?如何让我的方法在另一个访问之前完全运行?
答案 0 :(得分:6)
synchronized
此处有无效果,因为在这两种情况下您都没有在同一个对象上进行同步。应用于实例方法时,synchronized
关键字会导致该方法在this
上同步。因此,在每种情况下,您都在thread1
的实例上进行同步,其中有两个。
当您同时在两个线程中运行thread1
的相同实例时,将会有更有趣的测试。在这种情况下,调用wait(1000)
是一件非常糟糕的事情,因为(如文档所述)它会释放this
上的锁。您希望在代码中使用Thread.sleep(1000)
。
如果您需要有两个thread1
实例,则需要在某些共享对象上进行同步,可能是这样的:
private static final Object lockObject = new Object();
public void setName(String newName) {
synchronized(lockObject) {
doSetName(newName);
}
}
答案 1 :(得分:1)
您必须删除对等待(1000)的调用。看起来你真正想要的是调用 Thread.sleep(1000),如果你只想暂停当前线程,这不会释放任何监视器的所有权。
来自Object.wait()的javadoc。
此方法使当前线程(称为T)置于其中 等待该对象的设置,然后放弃任何和所有 同步声明此对象。线程T被禁用 线程调度的目的和休眠直到四件事之一 发生的情况:
- 其他一些线程调用此对象的notify方法,并且线程T恰好被任意选为线程 唤醒。
- 其他一些线程调用此对象的notifyAll方法。
- 其他一些线程中断了线程T。
- 指定的实时时间已经或多或少。但是,如果超时为零,则不会采用实时时间 考虑和线程只是等待通知。
然后从该对象的等待集中删除线程T. 重新启用线程调度。然后它以通常的方式竞争 与其他线程有权在对象上同步;一旦它 已获得对象的所有控制权 该对象恢复到原状 - 即,到 调用wait方法时的情况。线程T. 然后从wait方法的调用返回。因此,返回时 从wait方法,对象的同步状态和 线程T与调用wait方法时完全一样。
更新:正如其他答案中所提到的,您没有在同一个对象上进行同步。一旦你这样做,由于我提到的问题,你仍然会遭受相同的输出。您需要同时修复所需的结果。
答案 2 :(得分:0)
输出正确,您正在创建不共享任何数据的独立线程。因此,两个线程都以第一个字符串开头,经过一段时间后,字符串会被更改并打印出来。
答案 3 :(得分:0)
您正在创建2个thread1
个对象。他们每个人都有自己的setNAme
方法。同步方法仅在对象上同步,而不是在类上同步。除非方法是静态的。
答案 4 :(得分:0)
这里有两个具有独立名称变量和独立监视器的线程,因此每个线程只访问自己的成员。如果你想让线程互相交互,你就必须实现这样的交互。
答案 5 :(得分:0)
您正在创建两个单独的thread1对象并运行它们。每个线程都有自己的name变量副本以及setName函数。使它们都是静态的,你会看到同步的效果。
答案 6 :(得分:0)
您正在锁定两个不同的对象实例,根本不需要任何同步。只有在处理共享数据时才需要进行同步。我想你打算写下面的测试。
如果你测试这个,你会发现第二个线程将等到第一个线程用synchronized方法完成。然后取出同步字,你会看到两个线程同时执行。
public class SynchronizeTest {
public static void main(String[] args) {
Data data = new Data();
Thread task1 = new Thread(new UpdateTask(data));
task1.start();
Thread task2 = new Thread(new UpdateTask(data));
task2.start();
}
}
class UpdateTask implements Runnable {
private Data data;
public UpdateTask(Data data) {
this.data = data;
}
public void run() {
try {
data.updateData();
} catch (Exception e) {
e.printStackTrace();
}
}
}
class Data {
public synchronized void updateData() throws InterruptedException {
for (int i = 0; i < 5; i++) {
Thread.sleep(5000);
System.out.println(i);
}
}
}