synchronized解决的问题
If two or more threads share an object, and more than one thread updates variables in that shared object, race conditions may occur.
如果多个线程共享对象,且多个线程对共享对象的变量作修改时,竞争情况就可能发生了。
synchronized含义
Q:What does ‘synchronized’ mean?
A:The synchronized keyword is all about different threads reading and writing to the same variables, objects and resources. This is not a trivial topic in Java, but here is a quote from Sun:
synchronized methods enable a simple strategy for preventing thread interference and memory consistency errors: if an object is visible to more than one thread, all reads or writes to that object's variables are done through synchronized methods.
In a very, very small nutshell: When you have two threads that are reading and writing to the same ‘resource’, say a variable named foo, you need to ensure that these threads access the variable in an atomic way. Without the synchronized keyword, your thread 1 may not see the change thread 2 made to foo, or worse, it may only be half changed. This would not be what you logically expect.
Again, this is a non-trivial topic in Java. To learn more, explore topics here on SO and the Interwebs about:
Concurrency
Java Memory Model
Keep exploring these topics until the name “Brian Goetz” becomes permanently associated with the term “concurrency” in your brain.
什么意思呢?
- 官方说了:synchronized方法是为了防止线程之间互相干涉以及内存一致性错误:当一个对象对于多个线程可见时,所有对于这个对象变量的读和写必须通过synchronized 方法。
具体情况是:举个栗子–当你有2个线程读写同一个‘资源’,比如说一个名为 ‘foo’的变量, 你需要确保这些线程以一种原子操作访问该变量。如果没有用synchronized关键字,thread1可能看不到thread2对于变量’foo’所做的变化,更有甚者,thread1可能只看到了thread2对’foo’所作改变的一部分。这显然不是我们想要的结果!
少年,努力吧,等你达到了大佬“Brain Goetz”的高度,你就和并发合体了����…
synchronized实例
- 实例一
代码:
package com.fqy.cave;
/*
* synchronized keyword here is to deal with sharing resource issue.
*/
public class SynDemo {
private int count = 0;
// synchronized
public void /* synchronized */ increment() {
count++;
}
public void doWork() {
Thread t1 = new Thread(new Runnable() {
@Override
public void run() {
for (int i = 0; i < 1E4; i++)
increment();
}
});
Thread t2 = new Thread(new Runnable() {
@Override
public void run() {
for (int i = 0; i < 1E4; i++)
increment();
}
});
t1.start();
t2.start();
try {
t1.join();
t2.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
/*
* 如果没有synchronized同步该方法时,结果不是2000. Why?
* 1.线程对于共享对象变量的操作并不是原子的。3步,读取-加1-赋值。 2. 不知道何时从cache将值写入主存,所以出现了如下结果:
* main 1543(sometimes) 这就是所谓的:修改了部分值
*/
System.out.println(Thread.currentThread().getName() + " " + count);
}
public static void main(String[] args) {
new SynDemo().doWork();
}
}
结果:
main 13166
2. 实例二
代码:
package com.fqy.cave;
/*
* synchronized means that in a multi threaded environment, an object having
* synchronized method(s)/block(s) does not let two threads to access the
* synchronized method(s)/block(s) of code at the same time. This means that
* one thread can't read while another thread updates it.
*/
public class TestSyn {
public static void main(String[] args) {
TestSynUtil.demonstrate();
}
}
class TestSynUtil {
public static void demonstrate() {
SharedObject sharedObject = new SharedObject();
Thread t1 = new TestSynDemo(sharedObject, "Thread1");
Thread t2 = new TestSynDemo(sharedObject, "Thread2");
Thread t3 = new TestSynDemo(sharedObject, "Thread3");
t1.start();
t2.start();
t3.start();
try {
t1.join();
t2.join();
t3.join();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
class SharedObject {
// if not with synchronized keyword, result will be totally different
public synchronized void test(String name) {
for (int i = 0; i < 5; i++) {
System.out.println(name + ": " + i);
try {
Thread.sleep(100);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
class TestSynDemo extends Thread {
private SharedObject sharedObject;
private String name;
public TestSynDemo(SharedObject sharedObject, String name) {
this.sharedObject = sharedObject;
this.name = name;
}
@Override
public void run() {
sharedObject.test(name);
}
}
结果:
Thread1: 0
Thread1: 1
Thread1: 2
Thread1: 3
Thread1: 4
Thread3: 0
Thread3: 1
Thread3: 2
Thread3: 3
Thread3: 4
Thread2: 0
Thread2: 1
Thread2: 2
Thread2: 3
Thread2: 4
Otherwise:
Thread2: 0
Thread1: 0
Thread3: 0
Thread1: 1
Thread3: 1
Thread2: 1
Thread1: 2
Thread2: 2
Thread3: 2
Thread1: 3
Thread2: 3
Thread3: 3
Thread2: 4
Thread1: 4
Thread3: 4