问题描述
同步适用于以下代码。
public class Main implements Runnable {
public static void main(String[] args) {
Main m = new Main();
for (int i = 0; i < 2; i++) {
Thread t = new Thread(m);
t.start();
}
}
@Override
public void run() {
synchronized(this) {
for (int i = 0; i < 500; i++) {
System.out.println(i);
}
}
}
}
// Synchronization isn't working here.
public class Main implements Runnable {
public static void main(String[] args) {
for (int i = 0; i < 2; i++) {
Thread t = new Thread(new Main());
t.start();
}
}
@Override
public void run() {
synchronized(this) {
for (int i = 0; i < 500; i++) {
System.out.println(i);
}
}
}
}
在一次采访中询问了这个问题。 我对此有点困惑,所以我试图理解为什么同步不能与第二个代码片段一起使用。 任何人都可以解释为什么同步不能与第二个代码片段一起使用?
1楼
因为如果您正在处理单个对象,则应用同步。
在第一种情况下,你有一个Main的单个可运行对象,即m
在第二种情况下,您有Main的独立对象。
for(int i=0;i<2;i++){
Thread t = new Thread(new Main()); // independent objects for each thread
t.start();
}
阐释:
如果你看到下面的代码,你会发现
synchronized (this) {
this
指的是对象本身。
因此,基于此对象应用锁定。
因此,在多个Main类对象的情况下,它们独立工作,而单一对象同步仅适用于该对象。
有关更多信息,请参阅:
文档中的代码
public class MsLunch {
private long c1 = 0;
private long c2 = 0;
private Object lock1 = new Object();
private Object lock2 = new Object();
public void inc1() {
synchronized(lock1) { // lock is acquired using lock1 object
c1++;
}
}
public void inc2() {
synchronized(lock2) { // lock is acquired using lock1 object
c2++;
}
}
}
在此示例中,您可以同时使用单个对象调用方法inc1()
和inc2()
,因为在不同对象上获取了锁。
这将有助于您更好地理解它。
所以你的情况锁定在获得this
(对象本身)。
因此,只要你有多个对象,它就可以独立工作,当你拥有单个对象时,它将同步工作。
2楼
您在此处创建两个对象。
如果多个线程试图访问它,则synchronized(this)
块将同步对同一对象的访问。
3楼
synchronized (this)
“this”是当前的对象实例。 在第一个示例中,在调用线程之前创建Main类的实例,并使用相同的实例。 因此同步工作。 但是在第二个例子中,在main()循环的每次迭代中,都创建了Main的新实例。 synchronized(this)将无法工作,因为Main类有多个实例。
4楼
在Java中, syncronized(object)
实际上是使用object
作为syncronized
代码块的独占锁。
如果我们将锁显式化,并观察在每种情况下创建了多少锁的实例,为什么第二个版本不起作用可能更为明显:
public class Lock {
}
public class Main(Lock lock) implements Runnable {
public static void main(String[] args) {
correct()
incorrect()
}
public static void incorrect() {
for (int i = 0; i < 2; i++) {
//New lock created each iteration
Main m = new Main(new Lock())
Thread t = new Thread(m);
t.start();
}
}
public static void correct() {
//One lock used for all iterations
Main m = new Main(new Lock())
for (int i = 0; i < 2; i++) {
Thread t = new Thread(m);
t.start();
}
}
@Override
public void run() {
synchronized(lock) {
for (int i = 0; i < 500; i++) {
System.out.println(i);
}
}
}
}
5楼
// Synchronization isn't working here.
public class Main implements Runnable {
public static void main(String[] args) {
for (int i = 0; i < 2; i++) {
Thread t = new Thread(new Main());
t.start();
}
}
@Override
public void run() {
synchronized(this) {
for (int i = 0; i < 500; i++) {
System.out.println(i);
}
}
}
}
在上面的例子中有3个线程和3个Main对象,每个线程对不同的Main对象进行锁定,因此同步不起作用。为了使同步工作,我们应该让所有线程对单个对象进行锁定。 这里有3个线程没有锁定单个对象,而是3个不同的对象。 每个线程都锁定每个主要对象,这些主要对象不在线程之间共享。 在Thread t = new Thread(m); 所有线程都锁定单个Main(m)对象。
6楼
我会用自己的问题回答这个问题:
你是什么意思,它不工作 ?
第一个示例序列化System.out.println()
调用,并且由于此处的其他几个答案中给出的原因,第二个示例没有序列化调用,但那又如何呢?
System.out
是一个java.io.PrintWriter
,而PrintWriter
本质上是线程安全的。
这两个例子都不需要同步。