线程安全
产生线程安全问题的三个条件
1.多个线程
2.多条语句操作共享语句
3.修改共享数据的代码
多线程中可能出现的问题
三个线程共享一个数据时,会产生的问题,买票会多卖一张
public static void main(String[] args) throws InterruptedException {
B b1 = new B();
Thread a1 = new Thread(b1, "wei1");
Thread a2 = new Thread(b1, "wei2");
Thread a3 = new Thread(b1, "wei3");
a1.start();
a2.start();
a3.start();
}
class B implements Runnable {
static int Piao = 100;
int t = 0;
public B() {
}
public B(int piao) {
Piao = piao;
}
@Override
public void run() {
while (true) {
if (Piao <= 0) break;
try {
Thread.sleep(100);
} catch (InterruptedException e) {
}
System.out.printf("%S : 卖出 %d座 的票,剩余票%d张\n ", Thread.currentThread().getName(), (t++), Piao--);
}
System.out.println(Thread.currentThread().getName() + " 线程结束!");
}
}
1.同步代码块解决线程安全
重写的run方法加上对象锁(此处的锁对象为同一个锁,不能是新对象)
@Override
public void run() {
while (true) {
synchronized (this) {
if (Piao <= 0) break;
System.out.printf("%S : 卖出 %d座 的票,剩余票%d张\n ", Thread.currentThread().getName(), (t++), Piao--);
try {
Thread.sleep(100);
} catch (InterruptedException e) {
}
}
}
System.out.println(Thread.currentThread().getName() + " 线程结束!");
}
2.同步方法
原理
因为每次创建新的实例所以需要采用静态方法调用类名.class作为锁对象。
@Override
public void run() {
while (true) {
if (Piao <= 0) break;
sall();
}
}
public static synchronized void sall() {
if (Piao <= 0)return;
System.out.printf("%S : 卖出 %d座 的票,剩余票%d张\n ", Thread.currentThread().getName(), (t++), --Piao);
try {
Thread.sleep(10);
} catch (InterruptedException e) {
}
}
3.Lock锁
锁上之后一定要记得开锁
@Override
public void run() {
while (true) {
lock.lock();
if (Piao <= 0) break;
System.out.printf("%S : 卖出 %d座 的票,剩余票%d张\n ", Thread.currentThread().getName(), (t++), --Piao);
lock.unlock();
try {
Thread.sleep(10);
} catch (InterruptedException e) {
}
}
System.out.println(Thread.currentThread().getName() + " 线程结束!");
}
但是程序本身并没有运行结束(因为当最后一次锁上之后票为0会跳出循环)
需要添加try/finally (ctrl + alt + t )
注: 三种代码原理基本类似,都是将代码块锁住等待执行完毕下一个进程继续进行