线程笔记二(线程安全)
如果有多个线程在同时运行,而这些线程可能会同时运行这段代码。程序每次运行结果和单线程运行的结果是一样 的,而且其他的变量的值也和预期的是一样的,就是线程安全的。
案例:电影院要卖票,我们模拟电影院的卖票过程。假设要播放的电影是 “葫芦娃大战奥特曼”,本次电影的座位共100个 (本场电影只能卖100张票)。
//Runable接口类
public class TicketImpl implements Runnable{
private int ticket=100;
@Override
public void run() {
while(ticket>0){
try {
Thread.sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+"卖出第:"+ticket+"张票");
ticket--;
}
}
}
//测试类
public class Test_Demo {
public static void main(String[] args) {
TicketImpl ticket = new TicketImpl();
new Thread(ticket).start();
new Thread(ticket).start();
new Thread(ticket).start();
}
}
运行结果:
<img src="images\线程安全_买票案例1.png" alt="60" style="zoom:60%;" />
结果出现了重复的票,和不存在的票,这显然是不安全的。
原因分析
线程安全原理.png解决方法
1.同步:
将访问共享数据的代码块抽取出来,放在一个方法中,在方法上添加synchronized修饰符
格式:定义方法的格式
修饰符 synchronized 返回值类型 方法名(参数列表){
可能会出现线程安全问题的代码(访问了共享数据的代码)
}
public class TicketImpl implements Runnable{
private static int ticket=100;
@Override
public void run() {
while(true){
saleTicket();
}
}
public static void saleTicket(){
synchronized(TicketImpl.class){
if (ticket>0){
try {
Thread.sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+
"卖出第:"+ticket+"张票");
ticket--;
}
}
}
}
或者这样写也可以
public class TicketImpl1 implements Runnable{
private static int ticket=100;
Object object=new Object();
@Override
public void run() {
while(true){
synchronized(object){
if (ticket>0){
try {
Thread.sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+
"卖出第:"+ticket+"张票");
ticket--;
}
}
}
}
}
2.使用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.在可能会出现安全问题的代码后调用Lock接口中的方法unlock释放锁
public class TicketImpl2 implements Runnable{
private static int ticket=100;
Object object=new Object();
Lock lock=new ReentrantLock();
@Override
public void run() {
while(true){
lock.lock();
if (ticket>0){
try {
Thread.sleep(10);
System.out.println(Thread.currentThread().getName()+
"卖出第:"+ticket+"张票");
ticket--;
} catch (InterruptedException e) {
e.printStackTrace();
}finally {
lock.unlock();
}
}
}
}
}
网友评论