多线程运行模式,一般有两种:
卖票属于多个线程共享一份资源。
拿卖票来举例子
显然不正确
因为两个线程共跑了20次
希望,两个线程共跑10次。
整改
package com.njwbhz.march.week2.part0310.Ticket;
class Ticket {
private int number = 10;
public int getNumber() {
return number;
}
public void setNumber(int number) {
this.number = number;
}
}
卖票线程
package com.njwbhz.march.week2.part0310.Ticket;
public class Seller implements Runnable {
Ticket ticket = new Ticket();
public Seller(Ticket ticket) {
this.ticket = ticket;
}
@Override
public void run() {
//synchronized (惟一的对象)
// synchronized (this) {//this指的是Seller,而Seller只有一个
// //把可能造成不安全事件的代码锁起来
// while (ticket.getNumber() > 0) {
// //卖一张票
// ticket.setNumber(ticket.getNumber() - 1);
System.out.println(Thread.currentThread().getName() + ":" + "卖了一张票,还剩下" + ticket.getNumber() + "张");
// try {
// Thread.sleep(500);
// } catch (InterruptedException e) {
// e.printStackTrace();
// }
// System.out.println(Thread.currentThread().getName() + ":" + "卖了一张票,还剩下" + ticket.getNumber() + "张");
// }
// }
// while (ticket.getNumber() > 0) {
// synchronized (this) {
// //卖一张票
// ticket.setNumber(ticket.getNumber() - 1);
System.out.println(Thread.currentThread().getName() + ":" + "卖了一张票,还剩下" + ticket.getNumber() + "张");
// try {
// Thread.sleep(500);
// } catch (InterruptedException e) {
// e.printStackTrace();
// }
// System.out.println(Thread.currentThread().getName() + ":" + "卖了一张票,还剩下" + ticket.getNumber() + "张");
// }
// }
//
while (true) {
synchronized (this) {
if (ticket.getNumber() <= 0) {
break;
}
//卖一张票
ticket.setNumber(ticket.getNumber() - 1);
// System.out.println(Thread.currentThread().getName() + ":" + "卖了一张票,还剩下" + ticket.getNumber() + "张");
try {
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + ":" + "卖了一张票,还剩下" + ticket.getNumber() + "张");
}
}
//锁的位置要适当
//锁的位置不对,仍然不安全
}
private synchronized void sell () {//Seller.class类锁
if (ticket.getNumber() == 0) {
System.exit(0);
}
if (ticket.getNumber() > 0){
//卖一张票
ticket.setNumber(ticket.getNumber() - 1);
// System.out.println(Thread.currentThread().getName() + ":" + "卖了一张票,还剩下" + ticket.getNumber() + "张");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + ":" + "卖了一张票,还剩下" + ticket.getNumber() + "张");
}
}
}
用两个窗口同时卖票,启动两个Seller线程
package com.njwbhz.march.week2.part0310.Ticket;
public class SellerApp {
public static void main(String[] args) {
//只new一次说明只有一份数据
Ticket ticket = new Ticket();
Seller seller = new Seller(ticket);
Thread t1 = new Thread(seller);
Thread t2 = new Thread(seller);
t1.setName("窗口张");
t2.setName("窗口李");
t1.start();
t2.start();
}
}
分析:为什么会造成数据不一致问题,CPU轮转不受程序员的控制。
当多个线程共享一份数据,且对数据发生修改操作时,会造成数据不安全,这种现象称为线程不安全事件,或线程同步问题。
怎么解决?
JDK中的锁机制
测试
至少看到一点进步,数据安全了,但是只能有一个线程做事。
synchronized 既可以锁代码块,也可以锁方法,最终能够保证数据的安全性。
synchronized牺牲了性能,提高了数据的安全性。
回顾集合框架
如何甄别线程同步问题
什么叫数据域?



