前面的买火车票的案例的代码存在线程安全问题
问题1:多个线程抢票出现相同的票数
问题2:出现错误票数,如:0,-1,-2等
原因:多个线程,在争抢资源的过程中,导致共享的资源出现问题,一个线程还没执行完,另一个线程就参与进来了,开始争抢
解决:在我的程序中,加入"锁"-->加同步-->同步监视器
方法1.同步代码块
实现Runnable接口
public class BuyTicketThread implements Runnable{
int ticketNum=10;
@Override
public void run() {
for (int i=1;i<=100;i++) {
synchronized (this) {//把具有安全隐患的代码锁住,如果锁多了就会效率低-->this 就是这个锁
if (ticketNum > 0) {
System.out.println("我在" + Thread.currentThread().getName() + "买到了" + (ticketNum--) + "票");
}
}
}
}
}
Thread
public class BuyTicketThread extends Thread{
static int ticketNum=10;
@Override
public void run() {
for (int i=1;i<=100;i++) {
synchronized (BuyTicketThread.class) {//锁必须多个线程用的是一把锁!!
if (ticketNum > 0) {
System.out.println("我在" + Thread.currentThread().getName() + "买到了" + (ticketNum--) + "票");
}
}
}
}
}
同步方法
Thread
public class BuyTicketThread extends Thread{
public BuyTicketThread(String name) {
super(name);
}
//一共10张票 加上static 修饰 为多个对象共享10张票
static int ticketNum=10;//每个窗口都是一个线程对象:每个对象执行的代码放入run方法中
@Override
public void run() {
for (int i=1;i<=100;i++) {
buyTicket();
}
}
//没有static 修饰也是锁住当前对象但问题没解决,,static修饰 -->多个对象共享一个锁
public static synchronized void buyTicket(){//锁住的是当前的这个对象this 同步监视器:BuyTicketThread.class
if (ticketNum > 0) {
System.out.println("我在" + Thread.currentThread().getName() + "买到了" + (ticketNum--) + "票");
}
}
}
Runnable
public class BuyTicketThread implements Runnable{
int ticketNum=10;
@Override
public void run() {
for (int i=1;i<=100;i++) {
buyTicket();
}
}
public synchronized void buyTicket(){ //锁住当前调用方法的对象this
if (ticketNum > 0) {
System.out.println("我在" + Thread.currentThread().getName() + "买到了" + (ticketNum--) + "票");
}
}
}
总结1:
1.多线程在争抢资源,就要实现线程的同步(就要进行加锁,并且这个锁必须是共享的,必须是唯一的,咱们的锁一般都是引用数据类型的.
目的:解决了线程安全问题
总结2:关于同步方法
1.不要将run()定义为同步方法
2.非静态同步方法的同步监视器是this
静态同步方法的同步监视器是类名.class字节码信息对象
3.同步代码块的效率要高于同步方法
原因:同步方法是将线程挡在了方法的外部,而同步代码块将线程挡在了代码的外部,但却是方法的内部
4.同步方法的锁是this,一旦锁住一个方法,就锁住了所有的同步方法;
同步代码块只是锁住使用该同步监视器的代码块,而没有锁住使用其他监视器的代码块