标签:多个 就会 main 另一个 strong stat 现在 窗口 解决
---恢复内容开始---
线程安全问题:
概述:场景:电影院有一百张票,现在用一个窗口卖1-100号票,属于单线程问题,无线程安全问题
现在有两个窗口,分别卖1-50 和51-100号票,属于多线程问题,因为没有访问共享数
据,也不会有线程安全问题。但如果两个窗口卖的都是1-100号票,有共享数据,就会
有安全问题。
代码实现:
public class Sell implements Runnable { private int ticket=100; @Override public void run() { while (true){ if (ticket>0){ try { Thread.sleep(10); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("正在卖第"+ticket+"张票"); ticket--; } } } }
public static void main(String[] args) { Sell sell=new Sell(); Thread t1=new Thread(sell); Thread t2=new Thread(sell); Thread t3=new Thread(sell); t1.start(); t2.start(); t3.start(); //问题: //正在卖第100张票 // 正在卖第100张票 //正在卖第97张票 //正在卖第0张票 //正在卖第-1张票 }
出现问题的原因:重复票:多个线程同时执行。 错误票:大家都进入if语句后,一个线程先执行,已经--,另一个线程后执行,就会产生错误数据。
解决线程安全问题:
第一种方法:同步代码块。
格式: synchronized (锁对象) { 可能会出现线程安全问题的代码 }
注意:1、锁对象可以使用任意对象,但必须保证多个线程使用同一个锁对象。
2、锁对象作用:把同步代码块锁住,只让一个线程在同步代码块中执行。
public class Sell implements Runnable { private int ticket=100; Object obj=new Object(); @Override public void run() { while (true){ synchronized (obj){ if (ticket>0){ try { Thread.sleep(10); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("正在卖第"+ticket+"张票"); ticket--; } } } } }
同步技术原理:
使用了一个锁对象,这个锁对象叫同步锁。
三个线程一起争夺cpu的执行权,谁抢到了就执行run()。
t1抢到cpu执行权,执行run(),遇到synchronized时,检查是否有锁对象,发现有
,就会获取锁对象,继续执行代码。
t2抢到了cpu执行权,执行run(),遇到synchronized时,发现没有锁对象,会等到
t1归还锁对象后,获取锁对象,才能继续执行。
第二种方法:同步方法。
使用步骤:
1、把访问共享数据的代码提取出来,放到一个方法中。
2、在方法上加synchronized修饰符。
使用格式: 修饰符 synchronized 返回值类型 方法名 (){可能出问题的代码}
锁对象:this。
public class Sell implements Runnable {
private int ticket=100;
Object obj=new Object();
@Override
public void run() {
while (true){
sell();
}
}
public synchronized void sell(){
if (ticket>0){
try {
Thread.sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("正在卖第"+ticket+"张票");
ticket--;
}
}
}
第三种方法:静态方法。
上面的方法加上 static。
锁对象:this是创建对象后产生的,静态方法优先于对象,静态方法的锁对象是本类的class属性。
第四种方法: Lock 锁。
java.util.concurrent.Locks.Lock 接口。
Lock 提供了比synchronized更广泛的操作。
Lock中的方法:void Lock()获取锁。 void unLock() 释放锁。
实现类: java.util.concurrent.Locks.ReentrantLock implements Lock.
使用步骤:
1、在成员位置创建一个ReentrantLock对象
2、可能会出现安全问题的代码前调用Lock接口中的 Lock方法获取锁。
3、......后调用 unLock方法 释放锁。
public class Sell implements Runnable { private int ticket=100; Lock lock=new ReentrantLock(); @Override public void run() { while (true){ lock.lock(); if (ticket>0) { try { Thread.sleep(10); System.out.println("正在卖第" + ticket + "张票"); ticket--; } catch (InterruptedException e) { e.printStackTrace(); }finally { lock.unlock(); } } } } }
标签:多个 就会 main 另一个 strong stat 现在 窗口 解决
原文地址:https://www.cnblogs.com/zhangyuhao/p/10799585.html