synchronized加锁大概分为两类:(简介)
对象锁:包括方法锁(直接加在方法上,默认锁对象为this当前实例对象)和同步代码块锁(自己指定锁对象)【这是每个对象独有的,不同对象互相不影响】
类锁:指定synchronized修饰静态的方法(static方法)或指定锁的对象为class对象【这是给类的class对象加锁,是其他对象共用的类锁】
下面介绍详细用法:
对象锁:【注意:由于是对象锁,所以一下实例的多个线程引用的都是同一个对象,如果是不同对象那就不会有影响】
一、同步代码块
1、锁定当前对象this
package test_Synchronize; public class SynchronizedObectCodeBlock implements Runnable{ static SynchronizedObectCodeBlock instance = new SynchronizedObectCodeBlock(); public static void main(String[] args) throws InterruptedException { //引用同一个对象 Thread th1 = new Thread(instance,"线程1"); Thread th2 = new Thread(instance,"线程2"); th1.start(); th2.start(); while (th1.isAlive() || th2.isAlive()) { } System.out.println("finished"); } @Override public void run() { synchronized (this) { // Thread.currentThread()当前线程,.getName()名字 System.out.println("我是对象锁的代码块形式我叫" + Thread.currentThread().getName()); try { // 让线程休眠3秒 Thread.sleep(3000); System.out.println("线程休息三秒后"); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } System.out.println(Thread.currentThread().getName() + "运行结束"); } } }
输出结果:
当把同步代码注释掉后的结果为:
2、锁定不同的对象 package test_Synchronize;
public class SynchronizedObectCodeBlock implements Runnable{
static SynchronizedObectCodeBlock instance = new SynchronizedObectCodeBlock();
Object lock1=new Object();
Object lock2=new Object();
public static void main(String[] args) throws InterruptedException {
Thread th1 = new Thread(instance,"线程1");
Thread th2 = new Thread(instance,"线程2");
th1.start();
th2.start();
while (th1.isAlive() || th2.isAlive()) {
}
System.out.println("finished");
}
@Override
public void run() {
synchronized (lock1) {
// Thread.currentThread()当前线程,.getName()名字
System.out.println("我是lock1对象锁的代码块形式我叫" + Thread.currentThread().getName());
try {
// 让线程休眠3秒
Thread.sleep(3000);
System.out.println("lock1锁-"+Thread.currentThread().getName()+"休息三秒后");
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println("lock1锁-"+Thread.currentThread().getName() + "运行结束");
}
synchronized (lock2) {
// Thread.currentThread()当前线程,.getName()名字
System.out.println("我是lock2对象锁的代码块形式我叫" + Thread.currentThread().getName());
try {
// 让线程休眠3秒
Thread.sleep(3000);
System.out.println("lock2锁-"+Thread.currentThread().getName()+"休息三秒后");
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println("lock2锁-"+Thread.currentThread().getName() + "运行结束");
}
}
}
运行结果:
解析:因为lock1和lock2是在线程中都是lock1先行再执行lock2,所以是按顺序运行的,也就是lock1完成后才会走lock2,而不同线程是会争同一个lock1锁的,所以必须一个线程的lock1锁释放后另一个线程才能运行。且4、5行是同时运行的,因为此时一个线程拿的是lock1锁,一个拿的是lock2锁,互不影响,所以是并行的。
二、方法锁:只能修饰普通方法,对象默认是this
package test_Synchronize; public class SynchronizedObjectMethod implements Runnable{ static SynchronizedObjectMethod intance=new SynchronizedObjectMethod(); public static void main(String[] args) { //【注意,线程引用的是同一个对象】 Thread th1=new Thread(intance,"线程1"); Thread th2=new Thread(intance,"线程2"); th1.start(); th2.start(); while(th1.isAlive() || th2.isAlive()){ } System.out.println("finished"); } public void run() { method(); } public synchronized void method(){ System.out.println("我是对象锁的方法修饰符形式,我叫:"+Thread.currentThread().getName()); try { Thread.sleep(3000); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } System.out.println(Thread.currentThread().getName()+"结束"); } }
运行结果:
类锁【不同于对象锁,以下线程引用的是不同的对象】
概念:
a、只有一个class对象:java类可能会有很多个对象,但是只有1个class对象。【class类是java中存在的,class对象存放你自己写的类的所有信息,class对象保存在.class字节码文件中】
b、本质:所以所谓的类锁,不过是class对象的锁而已。
c、用法和效果:类锁只能在同一时刻被一个对象拥有
b、本质:所以所谓的类锁,不过是class对象的锁而已。
c、用法和效果:类锁只能在同一时刻被一个对象拥有
一、synchronize加在static方法上。
package test_Synchronize; public class SynchronizedClassStatic implements Runnable{ static SynchronizedClassStatic instance1 = new SynchronizedClassStatic(); static SynchronizedClassStatic instance2 = new SynchronizedClassStatic(); public static void main(String[] args) { Thread th1 = new Thread(instance1,"线程1"); Thread th2 = new Thread(instance2,"线程2"); th1.start(); th2.start(); while (th1.isAlive() || th2.isAlive()) { } System.out.println("finished"); } public void run() { method(); } public static synchronized void method(){ System.out.println("我是类锁的第一种形式,static形式,我叫:"+Thread.currentThread().getName()); try { Thread.sleep(3000); System.out.println(Thread.currentThread().getName()+"三秒后"); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } System.out.println(Thread.currentThread().getName()+"结束"); } }
运行结果:
如果去掉了static的运行结果:
二、synchronize(*.class)代码块
.class表示用字面常量的方式获取Class对象的引用
package test_Synchronize; public class SynchronizeClassClass implements Runnable { static SynchronizeClassClass instanec = new SynchronizeClassClass(); static SynchronizeClassClass instanec2 = new SynchronizeClassClass(); public static void main(String[] args) { Thread th1 = new Thread(instanec,"线程1"); Thread th2 = new Thread(instanec2,"线程2"); th1.start(); th2.start(); while (th1.isAlive() || th2.isAlive()) { } System.out.println("finished"); } @Override public void run() { method(); } private void method() { synchronized (SynchronizeClassClass.class) { System.out.println("我是类锁的第二种形式,synchronize(*.class),我叫" + Thread.currentThread().getName()); try { Thread.sleep(3000); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } System.out.println(Thread.currentThread().getName()+"结束"); } } }
运行结果:
若把synchronized (SynchronizeClassClass.class)改成synchronized (this),结果为: