本篇我们来讲解synchronized关键字的四种加锁使用方式,并对其进行比较Github项目地址。
synchronized对方法加锁
public class SynchronizedTest {
static class Thread1 extends Thread {
Utils mUtils;
Thread1(Utils utils) {
mUtils = utils;
}
@Override
public void run() {
super.run();
mUtils.method1();
}
}
static class Thread2 extends Thread {
Utils mUtils;
Thread2(Utils utils) {
mUtils = utils;
}
@Override
public void run() {
super.run();
mUtils.method2();
}
}
static class Utils {
synchronized void method1() {
System.out.println("method1 exec before -- threadName:" + Thread.currentThread().getName());
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("method1 exec after-- threadName:" + Thread.currentThread().getName());
}
synchronized void method2() {
System.out.println("method2 exec before -- threadName:" + Thread.currentThread().getName());
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("method2 exec after-- threadName:" + Thread.currentThread().getName());
}
}
public static void main(String[] args) {
Utils utils = new Utils();
Utils utils2 = new Utils();
Thread thread1 = new Thread1(utils);
Thread thread2 = new Thread2(utils2);
thread1.start();
thread2.start();
}
}
//执行结果
method1 exec before -- threadName:Thread-0
method2 exec before -- threadName:Thread-1
method1 exec after-- threadName:Thread-0
method2 exec after-- threadName:Thread-1
- 我们看到如果对方法整体加锁的话,线程中如果不是同一个Utils对象的话,那么线程0和线程1其实是并行的,并没有达到同步的目的。如果我们仅仅修改运行代码如下,使得传入的对象为同一个对象的话,那么就是同步的效果,如下看到是线程1执行完毕,然后线程2才开始执行:
public static void main(String[] args) {
Utils utils = new Utils();
Thread thread1 = new Thread1(utils);
Thread thread2 = new Thread2(utils);
thread1.start();
thread2.start();
}
//执行结果
method1 exec before -- threadName:Thread-0
method1 exec after-- threadName:Thread-0
method2 exec before -- threadName:Thread-1
method2 exec after-- threadName:Thread-1
使用synchronized(this)
public class SynchronizedTest2 {
static class Thread1 extends Thread {
Utils mUtils;
Thread1(Utils utils) {
mUtils = utils;
}
@Override
public void run() {
super.run();
mUtils.method1();
}
}
static class Thread2 extends Thread {
Utils mUtils;
Thread2(Utils utils) {
mUtils = utils;
}
@Override
public void run() {
super.run();
mUtils.method2();
}
}
static class Utils {
void method1() {
synchronized (Utils.this) {
System.out.println("method1 exec before -- threadName:" + Thread.currentThread().getName());
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("method1 exec after-- threadName:" + Thread.currentThread().getName());
}
}
void method2() {
synchronized (Utils.this) {
System.out.println("method2 exec before -- threadName:" + Thread.currentThread().getName());
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("method2 exec after-- threadName:" + Thread.currentThread().getName());
}
}
}
public static void main(String[] args) {
Utils utils = new Utils();
Thread thread1 = new Thread1(utils);
Thread thread2 = new Thread2(utils);
thread1.start();
thread2.start();
}
}
//执行结果
method1 exec before -- threadName:Thread-0
method1 exec after-- threadName:Thread-0
method2 exec before -- threadName:Thread-1
method2 exec after-- threadName:Thread-1
- synchronized(this)代码块加锁,传入同一个对象是同步,如果传入的不是同一个对象,如下所示,则是异步的(线程0和线程1并发执行)。
public static void main(String[] args) {
Utils utils = new Utils();
Utils utils2 = new Utils();
Thread thread1 = new Thread1(utils);
Thread thread2 = new Thread2(utils2);
thread1.start();
thread2.start();
}
//执行结果
method1 exec before -- threadName:Thread-0
method2 exec before -- threadName:Thread-1
method1 exec after-- threadName:Thread-0
method2 exec after-- threadName:Thread-1
使用synchronized(xxx.class)
public class SynchronizedTest3 {
static class Thread1 extends Thread {
Utils mUtils;
Thread1(Utils utils) {
mUtils = utils;
}
@Override
public void run() {
super.run();
mUtils.method1();
}
}
static class Thread2 extends Thread {
Utils mUtils;
Thread2(Utils utils) {
mUtils = utils;
}
@Override
public void run() {
super.run();
mUtils.method2();
}
}
static class Utils {
void method1() {
synchronized (Utils.class) {
System.out.println("method1 exec before -- threadName:" + Thread.currentThread().getName());
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("method1 exec after-- threadName:" + Thread.currentThread().getName());
}
}
void method2() {
synchronized (Utils.class) {
System.out.println("method2 exec before -- threadName:" + Thread.currentThread().getName());
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("method2 exec after-- threadName:" + Thread.currentThread().getName());
}
}
}
public static void main(String[] args) {
Utils utils = new Utils();
Thread thread1 = new Thread1(utils);
Thread thread2 = new Thread2(utils);
thread1.start();
thread2.start();
}
}
//执行结果
method1 exec before -- threadName:Thread-0
method1 exec after-- threadName:Thread-0
method2 exec before -- threadName:Thread-1
method2 exec after-- threadName:Thread-1
- synchronized(xxx.class)加锁方式, 不管线程中传入的是不是同一个对象,都是同步,上面是同一个对象是同步的效果,下面看传入的不是同一个对象的话,效果也是一样的同步。
public static void main(String[] args) {
Utils utils = new Utils();
Utils utils2 = new Utils();
Thread thread1 = new Thread1(utils);
Thread thread2 = new Thread2(utils2);
thread1.start();
thread2.start();
}
//执行结果
method1 exec before -- threadName:Thread-0
method1 exec after-- threadName:Thread-0
method2 exec before -- threadName:Thread-1
method2 exec after-- threadName:Thread-1
静态方法前加synchronized
因为静态方法可以直接用类名调用,所以就没有实例化对象,从测试来看也是同步的效果。
public class SynchronizedTest4 {
static class Thread1 extends Thread {
@Override
public void run() {
super.run();
Utils.method1();
}
}
static class Thread2 extends Thread {
@Override
public void run() {
super.run();
Utils.method2();
}
}
static class Utils {
synchronized static void method1() {
System.out.println("method1 exec before -- threadName:" + Thread.currentThread().getName());
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("method1 exec after-- threadName:" + Thread.currentThread().getName());
}
synchronized static void method2() {
System.out.println("method2 exec before -- threadName:" + Thread.currentThread().getName());
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("method2 exec after-- threadName:" + Thread.currentThread().getName());
}
}
//synchronized(xxx.class)加锁, 不管线程中传入的是不是同一个对象,都是同步
public static void main(String[] args) {
new Thread1().start();
new Thread2().start();
}
}
//执行结果
method1 exec before -- threadName:Thread-0
method1 exec after-- threadName:Thread-0
method2 exec before -- threadName:Thread-1
method2 exec after-- threadName:Thread-1
总结:
synchronized加锁方式 | 同步还是异步 |
---|---|
synchronized void methodName() | 线程中传入的是同一个对象同步,否则异步 |
synchronized(this) | 线程中传入的是同一个对象同步,否则异步 |
synchronized(xxx.class) | 不管线程中传入的是不是同一个对象,都是同步 |
synchronized static void methodName() | 同步 |