线程安全问题
线程的生命周期
线程的同步
安全问题:
多个线程执行的不确定性引起执行结果的不稳定
多个线程对数据的共享会造成操作的不完整性,会破坏数据。
举例和解决措施:
三个窗口卖票,不采取措施会出现重票,错票等问题
未加锁的原始代码:
/*
创建三个窗口卖票,总票数为100张,使用实现Runnable接口方式
存在线程的安全问题,后面解决
*/
//1、创建一个实现Runnable接口的子类
class Window implements Runnable{
private int ticket=100;
//2、子类中重写run方法,写任务代码
@Override
public void run() {
while(true){
if (ticket > 0) {
System.out.println(Thread.currentThread().getName() + ":卖票,票号为:" + ticket);
ticket--;
} else {
break;
}
}
}
}
public class Tickets {
public static void main(String[] args) {
//3、创建子类的对象
Window w=new Window();
//4、通过Thread类创建线程对象,并将该子类对象作为构造器的参数进行传递
Thread w1=new Thread(w);
Thread w2=new Thread(w);
Thread w3=new Thread(w);
w1.setName("窗口1");
w2.setName("窗口2");
w3.setName("窗口3");
//5、调用Thread类的start方法
w1.start();
w2.start();
w3.start();
}
}
运行结果:
问题产生原因:当某个线程操作车票的时候,尚未完成操作,其他线程就参与进来操作车票
解决措施:当一个线程a在操作车票的时候,其他线程不能参与进来,直到线程a操作完成,其他线程才可以开始 操作车票。
在Java中,通过同步机制来解决线程的安全问题
方式一:同步代码块
synchronized(同步监视器){
需要被同步的代码(操作共享数据的代码)
}
这里车票就是共享数据
同步监视器,通常称为锁。任何一个类的对象都可以充当锁
多个线程必须要共用同一把锁
class Window implements Runnable{
private int ticket=100;
Object obj=new Object();
//2、子类中重写run方法,写任务代码
@Override
public void run() {
while(true){
synchronized (obj) {
if (ticket > 0) {
System.out.println(Thread.currentThread().getName() + ":卖票,票号为:" + ticket);
ticket--;
} else {
break;
}
}
}
}
}
现在的运行结果:
可以看到安全问题得到解决
方式二:同步方法
同步方法仍然涉及到同步监视器,只是不需要我们显式的声明
非静态的同步方法,同步监视器是this
静态的同步方法,同步监视器是当前类本身
修改方法:
//1、创建一个实现Runnable接口的子类
class Window implements Runnable{
private int ticket=100;
//Object obj=new Object();
//2、子类中重写run方法,写任务代码
@Override
public void run() {
while(true){
//synchronized (obj) {
show();
//}
}
}
private synchronized void show(){
if (ticket > 0) {
System.out.println(Thread.currentThread().getName() + ":卖票,票号为:" + ticket);
ticket--;
}
}
}
结果如下: