synchronized详解
多个线程执行对同一个Java对象访问时候,为了保证数据的有效性,通常会使用synchronized关键字,俗称多线程安全。
synchronized从语法上一共有三种语法,修饰静态方法,修饰实例方法,在方法中使用代码块。
从锁住的对象来看两种:锁住类和和实例对象。
锁住实例对象:无论多少个线程使用同一个实例对象,都需要排队。但是多个线程使用多个对象,就不用排队了。
锁住类:无论多少个对象,只要对象都是一个类,多个线程使用多个对象,依旧要排队。
注意:一定要检查对象是不是实例对象,局部/静态变量是无法锁住的。

使用同步代码块
synchronized (this) {}–对象锁
public void m1(){
synchronized (this) {//这里的this锁住的是所在类的实例对象对象
...................;
}
}
//因为是对象锁。两个线程使用两个对象。就锁不住了。
Object obj = new Object(); synchronized(obj){…} 对象锁
Object lock1=new Object();//实例对象,不能是局部变量
public void m1(){//
synchronized (lock1){//这里的锁住的是lock1,本质锁住的是所在类的实例对象。
...................;
}
}
//因为是对象锁,两个线程使用两个对象,就锁不住了。
synchronized(.class){…} 类锁,锁的是这个类。
public void m1(){
synchronized (xxx.class) {//这里锁住的是xxx类。
...................;
}
}
//因为是类锁。只要对象是这个xxx类的,无论几个线程使用几个个对象。都可以锁。
修饰实例方法 对象锁
//修饰实例方法,本质还是对象锁。
public synchronized void m1(){
}
//多个线程使用多个对象,无法被锁。
修饰静态方法 类锁
//修饰静态方法,类锁。只要对象是这个类的,无论多少个对象,都会被锁。
public synchronized static void m1(){
}
测试代码
上述例子,可以用以下代码进行简单测试。
public class work01 {
public static void main(String[] args) throws InterruptedException {
MyThread myThread=new MyThread();//同一个对象
Thread t1=new Thread(myThread,"t1");Thread t2=new Thread(myThread,"t2");
t1.start();t2.start();
}
}
class MyThread extends Thread{
count c=new count();//必须是实例对象
public void run(){
c.m1();
}
}
class count{
public void m1(){
synchronized (this){
for (int i = 0; i <30 ;i++) {
System.out.println(Thread.currentThread().getName() + "-->" + i);
}
}
}
}
总结:
- 无论synchronized关键字加在方法上还是对象上,如果它作用的对象是非静态的,则它取得的锁是对象;如果synchronized作用的对象是一个静态方法或一个类,则它取得的锁是类,该类所有的对象同一把锁。
- 实现同步是要很大的系统开销作为代价的,可能造成死锁,所以尽量避免无谓的同步控制。
- 优先使用局部变量,局部变量在栈区,是不共享的,静态变量在方法区中,实例变量在堆中,堆和方法区都是共享的。
本文详细介绍了Java中synchronized的使用方式,包括同步代码块、对象锁、类锁、实例方法和静态方法的同步控制。强调了锁的对象是实例还是类的区别,并提醒开发者注意避免无谓的同步开销和潜在的死锁问题。

1378

被折叠的 条评论
为什么被折叠?



