synchronized 对象锁和类锁的区别

synchronized 对象锁和类锁的区别

synchronized 描述

一段synchronized的代码被一个线程执行之前,他要先拿到执行这段代码的权限, 在Java里边就是拿到某个同步对象的锁(一个对象只有一把锁); 如果这个时候同步对象的锁被其他线程拿走了,他(这个线程)就只能等了(线程阻塞在锁池等待队列中)。 取到锁后,他就开始执行同步代码(被synchronized修饰的代码); 线程执行完同步代码后马上就把锁还给同步对象,其他在锁池中等待的某个线程就可以拿到锁执行同步代码了。 这样就保证了同步代码在统一时刻只有一个线程在执行。

多线程的线程同步机制实际上是靠锁的概念来控制的。

对象锁

加锁非静态方法,即是对象锁。synchronized修饰非静态方法、同步代码块的synchronized (this)用法和synchronized (非this对象)的用法锁的是对象,线程想要执行对应同步代码,需要获得对象锁。

看一个例子

定义一个SysTask,加锁一个非静态方法doSomeThing()

package thread.demo;

/**
 * Created on 2018/5/31
 *
 * @author wang.teng
 */
public class SysTask {
    public synchronized void doSomeThing(){
        System.out.println("start thread name is :" + Thread.currentThread().getName());
        try {
            Thread.sleep(2000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("end thread name is :" + Thread.currentThread().getName());
    }
}

再创建一个测试类Test

package thread.demo;

/**
 * Created on 2018/5/31
 *
 * @author wang.teng
 */
public class Test {
    public static void main(String[] args) {
        SysTask sysTask = new SysTask();
        for (int i=0 ;i<3;i++){
          Thread thread = new Thread(new Runnable() {
                @Override
                public void run() {
                    sysTask.doSomeThing();
                }
            });
            thread.setName(i+"-name");
            thread.start();
        }
    }
}

结果:

start thread name is :0-name
end thread name is :0-name
start thread name is :2-name
end thread name is :2-name
start thread name is :1-name
end thread name is :1-name

很明显此处是同步的。因为此处循环里面的是同一个对象,而对象锁是锁住的对象,所以是同步的。

下面修改一下测试类:

public class Test {
    public static void main(String[] args) {
        for (int i = 0; i < 3; i++) {
            SysTask sysTask = new SysTask();
            Thread thread = new Thread(new Runnable() {
                @Override
                public void run() {
                    sysTask.doSomeThing();
                }
            });
            thread.setName(i + "-name");
            thread.start();
        }

    }
}

此时结果是:

start thread name is :0-name
start thread name is :1-name
start thread name is :2-name
end thread name is :0-name
end thread name is :1-name
end thread name is :2-name

此时是异步的,因为每次调用同步方法的时候都是实例化不同的对象。

类锁

加锁静态方法,即类锁。可以换个方向理解,静态方法其实就是类方法,所以加锁静态方法,即类锁。类锁的范围是整个实体类,即全局锁。

继续看例子:

package thread.demo;

/**
 * Created on 2018/5/31
 *
 * @author wang.teng
 */
public class SysTaskStatic {
    public synchronized static void doSomeThing(){
        System.out.println("start thread name is :" + Thread.currentThread().getName());
        try {
            Thread.sleep(2000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("end thread name is :" + Thread.currentThread().getName());
    }
}

测试类:

package thread.demo;

/**
 * Created on 2018/5/31
 *
 * @author wang.teng
 */
public class TestSatic {
    public static void main(String[] args) {
        for (int i = 0; i < 3; i++) {
            Thread thread = new Thread(new Runnable() {
                @Override
                public void run() {
                    SysTaskStatic.doSomeThing();
                }
            });
            thread.setName(i + "-name");
            thread.start();
        }

    }
}

结果是:

start thread name is :0-name
end thread name is :0-name
start thread name is :1-name
end thread name is :1-name
start thread name is :2-name
end thread name is :2-name

结果很明显,是同步的,可以看出来类锁是达到了全局的效果。

猜你喜欢

转载自blog.csdn.net/wagnteng/article/details/80529758