Java synchronized 关键字和Lock的随笔
最近客户300个人同时按下一个按钮,在执行到一个业务模块的时候出现了脏读。
?
package org.test.thread;public class Worker {public void executeJob() {// statement A check()....// statement B....// dao.save();}}??
比如上面的代码,第一个线程走到B了,第二个线程走到了A,check的地方。比如重复性check。如果第一个线程和第二个线程的查询主键相同。那么当线程1走到dao.save的地方,线程2刚好跳过check,也就是check无效化了。
?
于是,考虑用同步来解决。
?
到JDK5为止,java中实现线程安全起码有3种方法,ThreadLocal,synchronized关键字,Lock。?
?
ThreadLocal是一种用空间换时间的策略。即为每一个线程创建副本。不适用于我们现在碰到的问题。所以不展开。
?
synchronized关键字:
在java中,他可以是方法修饰符,也可以成为独立的同步块。而加在方法前时,有两种方法,一般的方法和同步方法。两种效果不同。如:
如下这种,
?
package org.test.thread;public class Worker {public synchronized void executeJob() {}}?
?相当于
?
?
package org.test.thread;public class Worker {public void executeJob() {synchronized(this) {}}}?而加在静态方法前
?
?
package org.test.thread;public class Worker {public static synchronized void executeJob() {}}?则相当于
?
package org.test.thread;public class Worker {public void executeJob() {synchronized(this.getClass()) {}}}?虽然我不推荐你这么认为。因为静态方法加同步和一般方法中用同步块锁定类,这两种方法的用法是完全不一样的,虽然他们锁定的对象是一样的(Class)。
?
要弄清楚他的锁定对象,我们来做个实验:
?
package org.test.thread;public class Worker {public synchronized void executeA(String name) {for (int i = 0; i < 10; i++) {System.out.println(name + "-executeA-" + i);try {Thread.sleep(500);} catch (InterruptedException e) {e.printStackTrace();}}}public synchronized void executeB(String name) {for (int i = 0; i < 10; i++) {System.out.println(name + "-executeB-" + i);try {Thread.sleep(500);} catch (InterruptedException e) {e.printStackTrace();}}}public synchronized static void executeC(String name) {for (int i = 0; i < 10; i++) {System.out.println(name + "-executeC-" + i);try {Thread.sleep(500);} catch (InterruptedException e) {e.printStackTrace();}}}private class SynchronizerWorkerA extends Thread {public void run() {executeA("thread1");}}private class SynchronizerWorkerB extends Thread {public void run() {executeB("thread2");}}private class SynchronizerWorkerC extends Thread {public void run() {executeC("thread3");}}public static void main(String args[]) {Worker worker = new Worker();worker.new SynchronizerWorkerA().start();worker.new SynchronizerWorkerB().start();worker.new SynchronizerWorkerC().start();}}?
结果:
?
thread1-executeA-0
thread3-executeC-0
thread1-executeA-1
thread3-executeC-1
thread1-executeA-2
thread3-executeC-2
thread1-executeA-3
thread3-executeC-3
thread1-executeA-4
thread3-executeC-4
thread1-executeA-5
thread3-executeC-5
thread1-executeA-6
thread3-executeC-6
thread1-executeA-7
thread3-executeC-7
thread1-executeA-8
thread3-executeC-8
thread1-executeA-9
thread3-executeC-9
thread2-executeB-0
thread2-executeB-1
thread2-executeB-2
thread2-executeB-3
thread2-executeB-4
thread2-executeB-5
thread2-executeB-6
thread2-executeB-7
thread2-executeB-8
thread2-executeB-9
package org.test.thread;public class Worker {public synchronized void executeA(String name) {for (int i = 0; i < 10; i++) {System.out.println(name + "-" + i);try {Thread.sleep(500);} catch (InterruptedException e) {e.printStackTrace();}}}public synchronized static void executeB(String name) {for (int i = 0; i < 10; i++) {System.out.println(name + "-" + i);try {Thread.sleep(500);} catch (InterruptedException e) {e.printStackTrace();}}}private class SynchronizerWorkerA extends Thread {private String name = null;public SynchronizerWorkerA(String name) {this.name = name;}public void run() {executeA(name);}}private class SynchronizerWorkerB extends Thread {private String name = null;public SynchronizerWorkerB(String name) {this.name = name;}public void run() {executeB(name);}}public static void main(String args[]) {new Worker().new SynchronizerWorkerA("thread1").start();new Worker().new SynchronizerWorkerA("thread2").start();new Worker().new SynchronizerWorkerB("thread3").start();new Worker().new SynchronizerWorkerB("thread4").start();}}?知道有什么区别吗?我们在一个类的不同对象之间用了同步。结果:thread1-0thread2-0thread3-0thread1-1thread2-1thread3-1thread1-2thread2-2thread3-2thread3-3thread2-3thread1-3thread3-4thread2-4thread1-4thread1-5thread3-5thread2-5thread2-6thread1-6thread3-6thread1-7thread2-7thread3-7thread1-8thread3-8thread2-8thread1-9thread3-9thread2-9thread4-0thread4-1thread4-2thread4-3thread4-4thread4-5thread4-6thread4-7thread4-8thread4-9package org.test.thread;import java.util.concurrent.locks.Lock;import java.util.concurrent.locks.ReentrantLock;public class Worker extends Thread {private final Lock reentrantLock = new ReentrantLock();private String name;public Worker(String name) {this.name = name;}public void executeJob() {try {reentrantLock.lock();for (int i = 0; i < 10; i++) {System.out.println(name + "-" + i);try {Thread.sleep(500);} catch (InterruptedException e) {e.printStackTrace();}}} finally {reentrantLock.unlock();}}public void run() {executeJob();}public static void main(String args[]) {new Worker("thread-1").start();new Worker("thread-2").start();}}?结果:thread-1-0thread-2-0thread-1-1thread-2-1thread-1-2thread-2-2thread-1-3thread-2-3thread-2-4thread-1-4thread-1-5thread-2-5thread-1-6thread-2-6thread-1-7thread-2-7thread-1-8thread-2-8thread-1-9thread-2-9package org.test.thread;import java.util.concurrent.locks.Lock;import java.util.concurrent.locks.ReentrantLock;public class Worker {private final Lock reentrantLock = new ReentrantLock();public void executeJob(String name) {try {reentrantLock.lock();for (int i = 0; i < 10; i++) {System.out.println(name + "-" + i);try {Thread.sleep(500);} catch (InterruptedException e) {e.printStackTrace();}}} finally {reentrantLock.unlock();}}private class WorkerThread extends Thread {private String name = null;public WorkerThread(String name) {this.name = name;}public void run() {executeJob(name);}}public static void main(String args[]) {Worker worker = new Worker();worker.new WorkerThread("thread1").start();worker.new WorkerThread("thread2").start();}}?结果为:thread1-0thread1-1thread1-2thread1-3thread1-4thread1-5thread1-6thread1-7thread1-8thread1-9thread2-0thread2-1thread2-2thread2-3thread2-4thread2-5thread2-6thread2-7thread2-8thread2-9看起作用了吧。或者将原代码的lock对象改为static的package org.test.thread;import java.util.concurrent.locks.Lock;import java.util.concurrent.locks.ReentrantLock;public class Worker extends Thread {private final static Lock reentrantLock = new ReentrantLock();private String name;public Worker(String name) {this.name = name;}public void executeJob() {try {reentrantLock.lock();for (int i = 0; i < 10; i++) {System.out.println(name + "-" + i);try {Thread.sleep(500);} catch (InterruptedException e) {e.printStackTrace();}}} finally {reentrantLock.unlock();}}public void run() {executeJob();}public static void main(String args[]) {new Worker("thread-1").start();new Worker("thread-2").start();}}?结果同上package org.test.thread;public class Worker extends Thread {private static Object reentrantLock = new Object();private String name;public Worker(String name) {this.name = name;}public void executeJob() {synchronized (reentrantLock) {for (int i = 0; i < 10; i++) {System.out.println(name + "-" + i);try {Thread.sleep(500);} catch (InterruptedException e) {e.printStackTrace();}}}}public void run() {executeJob();}public static void main(String args[]) {new Worker("thread-1").start();new Worker("thread-2").start();}}?Lock与synchronized的区别(仅列出主要的)1.当块被同步,如果不想等了,synchronized无法停止等待,也没办法得到锁,而Lock可以用tryLock方法轻松做到.2.性能上Lock更优添加了类似锁投票、定时锁等候和可中断锁等候的一些特性。此外,它还提供了在激烈争用情况下更佳的性能