您好,欢迎访问一九零五行业门户网

Java线程安全与同步实例分析

线程安全问题多个线程可能会共享(访问)同一个资源
比如访问同一个对象,同一个变量,同一个文件
当多个线程访问同一块资源时,很容易引发数据错乱和数据安全问题,称为线程安全问题
什么情况下会出现线程安全问题
多个线程共享同一个资源
且至少有一个线程正在执行写的操作
实例:存钱取钱问题分别有存钱和取钱2个线程
   存钱                      取钱
   线程1         余额         线程2
   1000  《----1000------》 1000
   1000+1000-----》2000
                500 《-----1000-500
正确:结束后余额应该是1500,而不是500
买票问题有卖票2个线程
   卖票                      卖票
   线程1         票数         线程2
   1000  《----1000------》 1000
   1000-1-----》999
                999 《-----1000-1
正确:结束后余额应该是998,而不是999
买票问题错误(未线程同步)实例:
public class love implements runnable{ private int piao=3000;//有3000张票 public boolean sale() {//ture代表还有票;false代表没有票了 if(piao<1) return false; piao--;//卖1张票 //细化piao--; //寄存器=piao; //寄存器=寄存器-1; //piao=寄存器; string sk =thread.currentthread().getname();//获取当前线程(买票窗口)的名字 system.out.println(sk+"卖了1张票,还剩下"+piao+"张"); return piao>1; } public void run() { while(sale());//循环执行;直至卖完票返回false }} public class main { public static void main(string[] a) { love tjlove =new love(); for(int i=1;i<=4;i++) {//循环4次;产生4个线程(窗口)卖票 thread tj = new thread(tjlove()); tj.setname(""+i); tj.start(); } }}
部分输出结果:
线程安全问题分析问题线程a和b对类中1个变量值为17进行+1操作
最终结果为2个18
解决方案加锁:
过程:首先线程a先访问到这个17,读上来后进行加锁并进去+1的操作改为18
并且17在加锁期间其它线程都不能访问
改完之后再进行写入,然后再解锁17
然后再由线程b去访问它,再进行加锁,重复上面操作变成19再解锁
这样做能保证在同一时间只有1个线程去访问它,这样就保证了安全;之前错误是由于这些线程一起去访问了它
线程同步刚刚所说的加锁操作便是线程同步技术
可以使用线程同步技术来解决线程安全问题
线程同步在java里有2种做法:
1.同步语句
2.同步方法
同步语句public class love implements runnable{ private int piao=3000;//本人cpu单核性能过强,数据量大些才能看到是4个线程在卖票 public boolean sale() { synchronized(this) {//1个线程获取这个对象的锁,并加锁; synchronized作用于整个语句 //this指向当前对象 //不能用new object();这样会产生新的对象,产生新的锁 //把this换成"123",效果基本一样;因为其存在常量值里,每次访问的对象一样 if(piao<1) return false; piao--; string sk =thread.currentthread().getname(); system.out.println(sk+"卖了1张票,还剩下"+piao+"张"); return piao>0; } } public void run() { while(sale()); }}
部分输出结果:
synchronize(obj)的原理1.每个对象都有一个与它相关的内部锁(intrinsic lock)或者叫监视器锁(monitor lock)
2.第一个执行到同步语句的线程可以获得 obj 的内部锁,在执行完同步语句中的代码后释放此锁
3.只要一个线程持有了内部锁,那么其它线程在同一时刻将无法再获得此锁
✓ 当它们试图获取此锁时,将会进入blocked状态
4.多个线程访问同一个 synchronized(obj)语句时
obj必须是同一个对象,才能起到同步的作用
同步方法public class love implements runnable{ private int piao=3000; public synchronized boolean sale() { //synchronized作用于整个方法 if(piao<1) return false; piao--; string sk =thread.currentthread().getname(); system.out.println(sk+"卖了1张票,还剩下"+piao+"张"); return piao>0; } public void run() { while(sale()); }}
synchronized不能修饰构造方法
同步方法的本质实例方法:synchronized (this)
静态方法:synchronized (class对象)
同步语句比同步方法更灵活一点
同步语句可以精确控制需要加锁的代码范围,减少处于blocked状态的线程,充分利用劳动力
使用了线程同步技术后
虽然解决了线程安全问题,但是降低了程序的执行效率
因为加了锁就会有处于等待的线程,多了加锁解锁的操作
所以在真正有必要的时候,才使用线程同步技术
以上就是java线程安全与同步实例分析的详细内容。
其它类似信息

推荐信息