Thread
synchronized
volatile
锁(Lock)
原子性(Atomic)
并发集合类
Excutors
每个java对象都有一个monitor,用来访问某段代码时避免其他对象访问这段代码。当某个monitor被一个线程占用,那么其他线程如果想访问由monitor控制的代码 则必须等待。通过synchronized实现,也可用wait notify来协作实现
1 volatile:
volatile的覆盖范围是变量级别的,同步代价低
volatile通知jvm将变量放到主存而不是放到工作内存,这样各个线程就是共享这个变量,进而可以直接读取
缺点:
容易出问题
难设计
存在脏数据,只保证了数据的可见性,无法保证原子性
CPU原语CAS配合volatile使用实现同步
CompareAndSet实现非阻塞算法
CAS 操作包含三个操作数 —— 内存位置(V)、预期原值(A)和新值(B)
结合AtomicInteger的同步实现来学习
非阻塞算法 (nonblocking algorithms)
具体参见:
http://blog.csdn.net/hsuxu/article/details/9467651
CAS缺点:
开销大,不停地循环
ABA问题
有ABA问题可以看出AutomicInteger不是严格意义上实现同步,可通过AtomicStampedReference加上版本控制来实现同,具体参见:
http://hustpawpaw.blog.163.com/blog/static/184228324201210811243127/
2 synchronized:
1 同步方法
锁定的是调用这个方法的对象 注意:对于同一个class的不同对象这种方法时不适用的
2 同步块
public void method(Object obj) {
synchronized(obj) {
}
}
谁拿到obj这个的锁谁就可以执行这块代码。obj是程序员指定的锁对象,一般是用byte[] lock = new byte[0],比较经济
3 作用于静态函数 和 class
synchronized放在静态函数前和synchronized锁xxxObject.class的效果是一样的,锁定的对象都是Class对象
记得在《Effective Java》一书中看到过将 Foo.class和 P1.getClass()用于作同步锁还不一样,不能用P1.getClass()来达到锁这个Class的目的。P1指的是由Foo类产生的对象。
可以推断:如果一个类中定义了一个synchronized的static函数A,也定义了一个synchronized 的instance函数B,那么这个类的同一对象Obj在多线程中分别访问A和B两个方法时,
不会构成同步,因为它们的锁都不一样。A方法的锁是Obj这个对象,而B的锁是Obj所属的那个Class。
这个我试了下貌似并不是这样effective说的这样
public class TestCAS {
int i = 0;
/**
* @param args
*/
public static void main(String[] args) {
AtomicInteger inta = new AtomicInteger();
inta.incrementAndGet();
final TestCAS t = new TestCAS();
final Class<?> test = TestCAS.class;
final Class<?> test1 = t.getClass();
System.out.println(test == test1);
new Thread(new Runnable() {
@Override
public void run() {
t.functionA(test);
}
}).start();
new Thread(new Runnable() {
@Override
public void run() {
t.functionB(test1);
}
}).start();
}
public void functionA(Class<?> clazz) {
synchronized (new TestCAS().getClass()) {
while(i<100) {
System.out.println("A " + i++);
}
}
}
public void functionB(Class<?> clazz) {
synchronized (TestCAS.class) {
while(i<100) {
System.out.println("B " + i++);
}
}
}
}
synchronized 适用于写大于读的情况下,当读取操作多于写操作时会有性能瓶颈,因为在读的时候其他线程也可以有读取操作。引出下面的的ReadWriteLock
3 ReadWriteLock
ReadWriteLock解决了synchronized可能会导致的性能瓶颈,当写操作时,其他线程无法读取或写入数据,而当读操作时,其它线程无法写入数据,但却可以读取数据
Java.util.concurrent.locks包中有个标准Lock接口。ReentrantLock 实现了Lock接口,它完全拥有synchronized的特性,同时还提供了新的功能:获取Lock的状态、非阻塞获取锁的方法tryLock()、可中断Lock。
本人在这里只是简单的学习ReentrantReadWriteLock的readLock()和writeLock()方法,这两个方法就可以解决synchronized的瓶颈问题
网上例子如下 原出处http://zk1878.iteye.com/blog/1005160
1.public class ReadWriteLockDemo {
2. static SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
3.
4. public static void main(String[] args) {
5. Data data = new Data();
6. Worker t1 = new Worker(data,true);
7. Worker t2 = new Worker(data,true);
8. t1.start();
9. t2.start();
10. }
11.
12. static class Worker extends Thread {
13. Data data;
14. boolean read;
15.
16. public Worker(Data data, boolean read) {
17. this.data = data;
18. this.read = read;
19. }
20.
21. public void run() {
22. if (read)
23. data.get();
24. else
25. data.set();
26. }
27. }
28.
29. static class Data {
30. ReadWriteLock lock = new ReentrantReadWriteLock();
31. Lock read = lock.readLock();
32. Lock write = lock.writeLock();
33. public void set() {
34. write.lock();
35. System.out.println(Thread.currentThread().hashCode()
36. + " set:begin " + sdf.format(new Date()));
37. try {
38. Thread.sleep(5000);
39. //
40. } catch (Exception e) {
41.
42. } finally {
43. System.out.println(Thread.currentThread().hashCode() + " set:end "
44. + sdf.format(new Date()));
45. write.unlock();
46. }
47.
48.
49. }
50.
51. public int get() {
52. read.lock();
53. System.out.println(Thread.currentThread().hashCode()
54. + " get :begin " + sdf.format(new Date()));
55. try {
56. Thread.sleep(5000);
57. //
58. } catch (Exception e) {
59.
60. } finally {
61. System.out.println(Thread.currentThread().hashCode() + " get :end "
62. + sdf.format(new Date()));
63. read.unlock();
64. }
65.
66.
67. return 1;
68. }
69. }
70.}