多线程
程序有没有存在安全隐患呢?
分析:
1,查看线程代码中是否有共享数据。
2,这个共享数据有没有被多条语句所操作。
发现,sum是共享数据。有两条语句在操作这个共享数据,如果这两条语句被多个线程分开执行。
也就是一个线程没有执行完,其他线程就参与执行,就容易发生安全问题.
解决办法:加入同步机制。 将需要被一个线程一次执行完的代码存储带同步代码块中 。
同步代码块是用于封装代码的。
而函数也是用封装代码的。所不同之处是同步带有锁机制。
那么如果让函数这个封装体具备同步的特性。不就可以取代同步代码块了吗?
怎么让函数具备同步性呢?
其实很简单,只要在函数上加上一个同步关键字修饰即可。
这就是同步的另一个体现形式:同步函数。
虽然同步的出现解决了线程安全问题。
但是也带来了一些弊端:
1,效率会降低。
2,容易引发死锁。
死锁经常出现的状况为:同步嵌套。
饿汉式
当多个线程并发执行getInstance方法时,容易发生线程安全问题。
因为s是共享数据,有多条语句在操作共享数据。
解决方式很简单。只要让getInstance方法具备同步性即可.
这虽然解决了线程安全问题,但是多个线程每一次获取该实例,都要
调用这个方法,每次调用都判断一次锁,所以效率会比较低.
为了保证安全,同时为了提高效率.可以通过双重判断的形式来完成。
原理:就是减少线程判断的锁次数。
虽然解决安全问题,也解决了效率问题,但是代码过多。
所以建议使用饿汉式体现单例设计模式。
验证静态同步函数到底用的是哪个锁?
静态同步函数使用的锁肯定不是this。
因为静态函数中不可以定义this。
静态随着类的加载而加载,这时有可能内容还没有该类对象对象。
但是一个类加载进内存,会先将这个类对应的字节码文件封装成对象。
该对象的表示方式 类名.class 代表一个类字节码文件对象,
该对象在内存中是唯一的。
静态同步函数使用的锁就是 该类对应字节码文件对象。 也就是 类名.class
同步函数和同步代码的区别:
同步代码块使用的锁可以是任意对象。
同步函数使用的锁是固定对象 this
所以一般定义同步时,建议使用 同步代码块. 当然,如果对象可以使用this。那么可以简化同步函数的形式。
等待/唤醒 机制
使用的方法是 :
wait():让线程等待。将线程存储到一个线程池中。
notify():唤醒被等待的线程。通常都唤醒线程池中的第一个。让被唤醒的线程处于临时阻塞状态。
notifyAll(): 唤醒所有的等待线程。将线程池中的所有线程都唤醒,让它们从冻结状体转到临时阻塞状态.
这三个方法用于操作线程,可是定义在了Object类中,为什么呢?
因为,这三个方法在使用时,都需要定义在同步中,要明确这些方法所操作的线程所属于锁。
简单说。在A锁被wait的线程,只能被A锁的notify方法唤醒。
所以必须要表示wait notify方法所属的锁对象,而锁对象可以是任意的对象。
可以被任意的对象调用的方法肯定定义在Object类中。