java-多线程-线程同步问题

来源:互联网 发布:中级经济师网络课程 编辑:程序博客网 时间:2024/06/04 19:38
*1.线程安全问题存在的原因?
* 由于一个线程在操作共享数据过程中,未执行完毕的情况下,另外的线程参与进来,导致共享数据存在了安全问题。这样的得到的错误数据在业务上称为脏数据;
*
* 2.如何来解决线程的安全问题?

* 必须让一个线程操作共享数据完毕以后,其它线程才有机会参与共享数据的操作。


1.比如:去银行取钱,A,B线程同时对账户1取钱,当线程A从账户1取出钱后,但还没来得及改变账户余额,CPU就切换成了B账户对账户1操作;此时就出现了线程安全问题;

2.解决办法:

* 方式一:同步代码块
监视器,锁的理解:占有。调用层使用的来保证类安全
Object someObject =new Object();
synchronized (someObject){
//此处的代码只有占有了someObject后才可以执行
}
其他线程如果要操作这个代码块,就必须等待占有someObject对象的线程释放someObject这个对象,只有等待这个代码块执行完之后,才能操作;synchronized表示当前线程,独占 对象 someObject
当前线程独占 了对象someObject,如果有其他线程试图占有对象someObject,就会等待,直到当前线程释放对someObject的占用。
someObject 又叫同步对象,所有的对象,都可以作为同步对象,为了达到同步的效果,必须使用同一个同步对象
* synchronized(同步监视器){//这里的同步监视器就是上面的someObject,一个对象;
* //需要被同步的代码块(即为操作共享数据的代码)
* }
* 1.共享数据:多个线程共同操作的同一个数据(变量)
* 2.同步监视器:由一个类的对象来充当。哪个线程获取此监视器,谁就执行大括号里被同步的代码。俗称:锁
* 要求:所有的线程必须共用同一把锁!
* 注:在实现的方式中,考虑同步的话,可以使用this来充当锁。但是在继承的方式中,慎用this!

* 方式二:同步方法:设计类的时候使这个类是线程安全的类
* 用synchronized来修饰实例方法(非static方法),同步方法的同步监视器就是this,就是调用这个方法的对象;
对于可变类和不可变类,不可变类的对象状态不可改变,所以总是线程安全的;
但是可变类,需要额外的方法来保证其线程安全;
如果一个类,其方法都是有synchronized修饰的,那么该类就叫做线程安全的类
同一时间,只有一个线程能够进入 这种类的一个实例 的去修改数据,进而保证了这个实例中的数据的安全(不会同时被多线程修改而变成脏数据)
比如StringBuffer和StringBuilder的区别
StringBuffer的方法都是有synchronized修饰的,StringBuffer就叫做线程安全的类
而StringBuilder就不是线程安全的类

注意:
1.只对共享资源进行同步,因为同步保证了线程安全,但是降低了程序的运行效率;
2.JDK中的StringBuffer和StringBuilder分别为多线程环境和单线程环境下使用的类;前者保证了多线程安全;所以可变类可以提供两种运行版本;

同步监视器的释放:
1.当前线程的同步方法或者同步代码块执行结束,就会释放同步监视器;
2.当前线程出现了错误,导致异常结束,会释放同步监视器;
3.当前线程的同步代码块活同步方法中调用了同步监视器对象的wait方法,则会暂停当前线程,并释放同步监视器;
然而!程序调用sleep,yield,suspend方法并不会释放同步监视器;

死锁:不同的线程占用着对方需要的共享 资源,都等着对方释放锁,形成了线程死锁;
释放同步对象的方式: synchronized 块自然结束,或者有异常抛出

死锁的四个必要条件和避免、预防死锁
避免死锁的银行家算法


0 0
原创粉丝点击