《java 多线程编程核心技术》读书笔记三

来源:互联网 发布:windows平板电脑2017 编辑:程序博客网 时间:2024/06/05 04:54

背景知识补充:

  1. 局部变量是线程安全的,局部变量属于线程私有的,在线程间不共享
  2. 类变量是非线程安全的,在多个实例之间、多个线程之间都是共享的
  3. 实例变量属于对象,在多个对象间不共享,当多个线程操作同一个对象的实例变量时,该变量将在多个线程中共享,则会导致非线程安全问题,但当多个线程分别操作同一个类的不同对象时,该变量只存在于当前线程中,故不会导致非线程安全问题

为了解决线程不安全的问题,java中提供了synchronized关键字,synchronized可以用于修饰方法或修饰代码块

synchronized 同步方法

其语法格式就是在方法前面加上synchronized关键字,如下:

synchronized public void methodName(){}

适用场景

当该方法内部有对共享资源进行读写操作时该方法就需要使用synchronized关键字修饰

synchronized取得的锁是对象锁,当一个线程调用对象的一个同步方法时,该线程将持有该对象的对象锁,其它线程可以直接调用该对象中没有被synchronized关键字修饰的方法,其它线程若要调用该对象中被synchronized关键字修饰的方法时,需要等待前一个线程释放该对象的对象锁后方可调用,在此之前只能排队等待

如果多个线程访问同一个类的多个对象,则JVM会创建多个锁

这里说的会创建多个锁,那这些锁是在什么时候创建的呢?

锁重入

前面背景知识提到当一个线程持有某个对象的对象锁时,其它线程若想获得该对象的对象锁则需要等待前一个线程释放对象锁后才可以获得。

现在我们来分析一个例子
有个类中含有两个被synchronized关键字修饰的方法,分别为methodA、methodB,methodA中调用methodB,此时程序还能正常执行吗?

public class Services {    synchronized public static void methodA(){        System.out.println("methodA");        new Services().methodB();    }    synchronized public void methodB(){        System.out.println("methodB");        methodC();    }    synchronized public void methodC(){        System.out.println("methodC");    }}public class MyThread extends Thread {    @Override    public void run() {        super.run();        Services services = new Services();        services.methodA();    }}public class Run {    public static void main(String[] args){        MyThread myThread = new MyThread();        myThread.start();    }}

这里涉及到锁重入的概念,那什么是锁重入呢?
当一个线程得到某对象的对象锁后,在还未释放该对象锁时该线程再次请求获取该对象的对象锁,是可以再次得到该对象的对象锁。即synchronized方法、synchronized代码块的内部调用本类的其它synchronized方法、synchronized代码块时,是永远可以得到对象锁的。
锁重入也适用于有父子关系的继承类中

锁释放

当synchronized方法、synchronize代码块执行完毕后该线程持有的对象锁将自动释放,除此之外,当synchronized方法、synchronized代码块中出现异常时,该线程持有的对象锁也将自动释放

synchronized关键字不具有继承性

父类中的synchronized方法在子类中重写时去掉了synchronized关键字,则子类中的该方法不具有同步功能

阅读全文
0 0