一、synchronized加锁方式
synchronized可以使多线程同步运行。
synchronized的使用时需要配合对象,即每一个synchronized修饰的方法或代码块都会配备一个对象,这个对象可以是实例对象也可以是类对象,类锁本质上也是Class类的实例对象。所以每一个synchronized都会跟一个实例对象对应。
synchronized修饰方法时,默认加的是当前对象实例的锁;修饰静态方法时默认加的是当前类的类对象的锁。修饰代码块和静态代码块,书写方式一样,不同的是所加的对象锁。
互斥规则:
1、当一个线程访问某对象的synchronized方法或代码块时,其他线程可以访问非synchronized方法或代码块,不会阻塞。
2、当锁是同一对象实例时,一个线程访问该对象的synchronized方法或代码块时,其他线程访问该对象的synchronized方法或代码块时,会被阻塞。
3、同一类的不同实例对象的对象锁互不干扰。
4、类锁也是一种特殊的对象锁,第2条同样适用,适用于静态方法和加了类锁的代码块。
5、类锁和对象锁互不干扰。
二、加锁实例
import lombok.SneakyThrows; public class SynchThread implements Runnable { @SneakyThrows @Override public void run() { if("static_method".equals(Thread.currentThread().getName())){ synchronizedStaticMethod(); }else if("no_static_method".equals(Thread.currentThread().getName())){ synchronizedMethod(); }else if ("static_block".equals(Thread.currentThread().getName())){ synchronized(SynchThread.class){ System.out.println(Thread.currentThread().getName()+" :synchronized静态代码块start....."); System.out.println(Thread.currentThread().getName()+" :synchronized静态代码块sleep....."); Thread.sleep(2000); System.out.println(Thread.currentThread().getName()+" :synchronized静态代码块voer!!!"); } }else if ("no_static_block".equals(Thread.currentThread().getName())){ synchronized (this){ System.out.println(Thread.currentThread().getName()+" :synchronized代码块start....."); System.out.println(Thread.currentThread().getName()+" :synchronized代码块sleep....."); Thread.sleep(2000); System.out.println(Thread.currentThread().getName()+" :synchronized代码块voer!!!"); } } } @SneakyThrows public synchronized void synchronizedMethod(){ System.out.println(Thread.currentThread().getName()+" :synchronized方法start...."); System.out.println(Thread.currentThread().getName()+" :synchronized方法sleep...."); Thread.sleep(2000); System.out.println(Thread.currentThread().getName()+" :synchronized方法voer!!!"); } @SneakyThrows public synchronized static void synchronizedStaticMethod(){ System.out.println(Thread.currentThread().getName()+" :synchronized静态方法start...."); System.out.println(Thread.currentThread().getName()+" :synchronized静态方法sleep...."); Thread.sleep(2000); System.out.println(Thread.currentThread().getName()+" :synchronized静态方法voer!!!"); } }
测试代码:
public class SynchThreadDome { public static void main(String[] args){ Runnable synchRun = new SynchThread(); Thread thread1 = new Thread(synchRun,"static_method"); Thread thread2 = new Thread(synchRun,"no_static_method"); Thread thread3 = new Thread(synchRun,"static_block"); Thread thread4 = new Thread(synchRun,"no_static_block"); thread1.start(); thread2.start(); thread3.start(); thread4.start(); } }
结果:
static_method :synchronized静态方法start.... static_method :synchronized静态方法sleep.... no_static_method :synchronized方法start.... no_static_method :synchronized方法sleep.... static_method :synchronized静态方法voer!!! static_block :synchronized静态代码块start..... static_block :synchronized静态代码块sleep..... no_static_method :synchronized方法voer!!! no_static_block :synchronized代码块start..... no_static_block :synchronized代码块sleep..... static_block :synchronized静态代码块voer!!! no_static_block :synchronized代码块voer!!!
上述结果可以看出:
1、静态方法(代码块)和非静态方法(代码块)的执行互不干扰。
2、静态方法和静态代码块之间相互阻塞;非静态方法和非静态代码块之间相互阻塞;
因为静态方法和静态代码块加的是this锁;非静态方法和非静态代码块加的是类锁(SynchThread.class)。
总结:从一个更加广义的角度看待锁的机制,上了同一个锁的多个线程,不管线程调用的是不是同一段逻辑,都会形成阻塞;未上相同锁的多个线程,相互运行不相干。
如下:
package test.thread; public class TestLock { public static void main(String[] args) { String str = new String(); System.out.println("aaa开始"); new Thread(new Runnable() { @Override public void run() { synchronized (str) { for (int i = 0; i < 100; i++) { System.out.println("aaaa"+i); } } } }).start(); System.out.println("bbb开始"); new Thread(new Runnable() { @Override public void run() { synchronized (str) { for (int i = 0; i < 100; i++) { System.out.println("bbbb"+i); } } } }).start(); } }
以上代码会在aaa0~aaa99输出完成后,在输出bbb0~bbb99.