方法同步vs代码块同步
关于同步方法和同步代码块的争论
- 同步方法获取的是整个对象的锁。这意味着,其他线程在该方法被运行时不能使用任何的同步方法。
- 同步代码块获取的是synchronized关键字后括号中的内容的关于该对象的锁。
所以:如果你想锁的是整个对象,用synchronized方法。如果你想保证对象的其他部分对其他线程可访问,则应当使用synchronized代码块。
取舍:如果你小心谨慎地选取被锁的对象,同步代码块将会产生更少的竞争,因为整个对象/class并没有被锁住。
这些同样应用于静态方法:同步静态方法将会锁住整个类对象;而同步代码块锁住的只是小括号之间的内容。
翻译过来后很生涩,如果实在看不下去,建议自己看英文版本的链接吧����。
#synchronized on multiple shared object
在多个对象上同步的另一应用:线程执行需要多种资源情形:
final Object foo;
final Object bar;
Runnable tObj = new Runnable {
public void run() {
while(true) {
//sync #1
synchronized(foo) {
synchronized(bar) {
//sync foo
}
}
//More code foo
//Some more code
//sync #2
synchronized(bar) {
synchronized(foo) {
//sync foo
}
}
}
}
}
Thread t1 = new Thread(tObj);
Thread t2 = new Thread(tObj);
这样问题就来了:死锁!!!
当运行到某个时间节点时有如下情形–t1得到了foo同时等待 t2释放bar;t2得到了bar同时等待 t1释放foo.
具体内容后面有涉及,这里有关于上述代码的完整讲解。
Show me the code
- 具体代码
package com.fqyuan.blog;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;
/*
* List 并不是线程安全的,所以多个线程对同一个list对象写操作时就可能出现异常。
* 1.这里可以直接synchronized process()方法,但这样多线程执行效率低下。
* 2.同样可以synchronized stageOne()和stageTwo(),同样多线程只是按顺序完成,效率低下。
* 3.所以这里应用的是代码块机制。
*/
public class SynOnMulti {
public static void main(String[] args) {
SynOnMultiUtil.demonstrate();
}
}
class SharedObject {
private List<Integer> list1 = new ArrayList<>();
private List<Integer> list2 = new ArrayList<>();
private Object lock1 = new Object();
private Object lock2 = new Object();
private Random random = new Random();
private /* synchronized */void stageOne() {
synchronized (lock1) {
try {
Thread.sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
list1.add(random.nextInt(100));
}
}
private /* synchronized */void stageTwo() {
synchronized (lock2) {
try {
Thread.sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
list2.add(random.nextInt(100));
}
}
public void process() {
for (int i = 0; i < 100; i++) {
stageOne();
stageTwo();
}
}
}
class SynOnMultiUtil {
public static void demonstrate() {
long startTime = System.currentTimeMillis();
SharedObject sharedObject = new SharedObject();
Thread t1 = new Thread(new Runnable() {
@Override
public void run() {
sharedObject.process();
}
});
Thread t2 = new Thread(new Runnable() {
@Override
public void run() {
sharedObject.process();
}
});
t1.start();
t2.start();
try {
t1.join();
t2.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
long endTime = System.currentTimeMillis();
System.out.println("Total time taken is: " + (endTime - startTime));
}
}
- 运行结果
- 不加同步机制:运行很快,但可能有异常。
Exception in thread "Thread-0" java.lang.ArrayIndexOutOfBoundsException: 109
at java.util.ArrayList.add(ArrayList.java:459)
at com.fqyuan.blog.SharedObject.stageOne(SynOnMulti.java:37)
at com.fqyuan.blog.SharedObject.process(SynOnMulti.java:54)
at com.fqyuan.blog.SynOnMultiUtil$1.run(SynOnMulti.java:67)
at java.lang.Thread.run(Thread.java:745)
Total time taken is: 2433
2.同步在process上
Total time taken is: 4711
3.理论结果
Total time taken is: 2432
Get detailed code and notes @ github.