我在java中编写了一些多线程代码,并且改变了变量的同步方法,但它没有同步我的代码,我仍然得到随机值。有我的代码:
public class Main {
public static void main(String[] args) throws Exception {
Resource.i = 5;
MyThread myThread = new MyThread();
myThread.setName("one");
MyThread myThread2 = new MyThread();
myThread.start();
myThread2.start();
myThread.join();
myThread2.join();
System.out.println(Resource.i);
}
}
class MyThread extends Thread {
@Override
public void run() {
synMethod();
}
private synchronized void synMethod() {
int i = Resource.i;
if(Thread.currentThread().getName().equals("one")) {
Thread.yield();
}
i++;
Resource.i = i;
}
}
class Resource {
static int i;
}
有时我得到7,有时是6,但是我已经同步了synMethod
,因为据我所知,在执行此方法时,没有任何线程应该使用此方法,因此操作应该是原子的,但它们是不,我不明白为什么?你可以向我解释一下,并回答 - 我该如何解决?
答案 0 :(得分:10)
添加synchronized
方法就像在this
上进行同步一样。由于你有两个不同的线程实例,它们不会互相锁定,这种同步并没有真正做任何事情。
为了使同步生效,您应该在某些共享资源上进行同步。在您的示例中,Resource.class
可以是一个不错的选择:
private void synMethod() { // Not defined as synchronized
// Synchronization done here:
synchronized (Resource.class) {
int i = Resource.i;
if (Thread.currentThread().getName().equals("one")) {
Thread.yield();
}
i++;
Resource.i = i;
}
}
答案 1 :(得分:1)
让我们看一下oracle文档页面中synchronized methods的定义。
制作方法synchronized
有两个影响:
首先,对同一对象的两个同步方法的调用不可能进行交错。当一个线程正在为对象执行同步方法时,所有其他线程都会调用同一对象的同步方法阻塞(暂停执行),直到第一个线程完成对象为止。
回到您的查询:
synMethod()
是同步的方法对象级别。访问相同synchronized
方法的两个线程以顺序方式获取对象锁。但是,在没有共享锁的情况下,访问不同实例(对象)的同步方法的两个线程异步运行。
myThread
和myThread2
是两个不同的对象=>内部锁是在两个不同的对象中获取的,因此您可以异步访问这些方法。
一种解决方案:由Mureinik引用,使用共享对象进行锁定。
其他解决方案:使用更好的并发构造,如ReentrantLock等。
您在相关的SE问题中找到了更多替代方案: