多个线程同时操作一个共享数据时,就有可能造成错误,如重复操作,多于操作,例子:100张票,三个线程同时抢,那么就可能出现两个线程显示拿到了同一张票,但是每一张票有且只有一张欧,如下:
- 和计算机操作系统中出现的问题一样,一线程执行到
ticket++
时停止了,二线程在运行时也执行到ticket++
,然后一线程再拿到cpu继续开始运行下面的代码,此时就会出错,因为,ticket++
了两次,和一线程预期的样子偏离了- 对了,
ticket
应当被静态修饰,否则不同线程进来拿的将不是同一个ticket
package com.itjh.pojo;public class Ticket extends Thread{static int ticket=0;public Ticket(String name){super(name);}public void run(){while(true){if (ticket<50){ticket++;System.out.println(getName()+"。。。正在贩卖第"+ticket+"张票");try {Thread.sleep(200);} catch (InterruptedException e) {e.printStackTrace();}}else {break;}}}
}
测试类(三个线程):
package com.itjh.Test;import com.itjh.pojo.Ticket;public class TestTicket {public static void main(String[] args) {Ticket ticket1=new Ticket("小飞棍");ticket1.start();Ticket ticket2=new Ticket("小菁菁");ticket2.start();Ticket ticket3=new Ticket("小赤佬");ticket3.start();}
}
结果:出现了同一张票被多个线程拿到,别的情况就在这展示了
小菁菁。。。正在贩卖第196张票
小赤佬。。。正在贩卖第196张票
小飞棍。。。正在贩卖第197张票
小赤佬。。。正在贩卖第198张票
小菁菁。。。正在贩卖第198张票
小飞棍。。。正在贩卖第199张票
小赤佬。。。正在贩卖第199张票
小菁菁。。。正在贩卖第200张票Process finished with exit code 0
解决办法:
- 加入synchronized锁,进来一个线程就会上锁,直到此线程退出来为止
synchronized()
中应当添加静态对象(参数可以使用Object类的对象,记得加static
)因为只有静态的 才会是唯一的,否则锁会不唯一,那么锁就失去效果了
package com.itjh.pojo;public class Ticket extends Thread{static int ticket=0;public Ticket(String name){super(name);}static Object object=new Object();public void run(){while(true){synchronized (object){if (ticket<200){ticket++;System.out.println(getName()+"。。。正在贩卖第"+ticket+"张票");try {Thread.sleep(50);} catch (InterruptedException e) {e.printStackTrace();}}else {break;}}}}
}
synchronized()
锁:
- 唯一的,可以用静态的对象来满足,当然也可以用当前类的字节码文件,因为这个一定是唯一的,即
当前类.class
- 关闭锁这个操作是自动的
- 也可以添加在方法上,如
public synchronized void show(){ }
和上面的
synchronized
相比,Lock锁的开关是手动的
package com.itjh.pojo;import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;public class Ticket extends Thread{static int ticket=0;public Ticket(String name){super(name);}Lock lock=new ReentrantLock();public void run(){while(true){lock.lock(); {if (ticket < 50) {ticket++;System.out.println(getName() + "。。。正在贩卖第" + ticket + "张票");try {Thread.sleep(50);} catch (InterruptedException e) {e.printStackTrace();}} else {break;}}lock.unlock();}}
}
问题:
有可能在第49张票时一线程结束了,然后一线程又抢到了cpu那么就会执行
break
方法,于是lock.unlock();
就不会被执行了,于是锁没管,代码一直运行,即使没有进行实际的操作,如图
解决办法:
利用
finally{}
方法,将lock.unlock();
放进去就行