多线程卖票问题
1.实现多线程卖票
package com.cjj.duoxiancheng;
/*
* 路人假helloWorld
* 模拟卖票,三个窗口
* 存在线程的安全问题,待解决。
* */
class Window extends Thread{
//设置总票数100张
private static int ticket = 100;
@Override
public void run() {
while(ticket > 0){
System.out.println(Thread.currentThread().getName()+"买票,票号为:" + ticket);
ticket--;
}
}
}
public class WindowTest {
public static void main(String[] args) {
Window t1 = new Window();
Window t2 = new Window();
Window t3 = new Window();
t1.setName("窗口1");
t2.setName("窗口2");
t3.setName("窗口3");
t1.start();
t2.start();
t3.start();
}
}
运行结果如图:
可以看出100号票卖出了三张,证明程序存在线程安全问题。
2.解决方式
2.1 同步代码块
1.实现Runnable接口,可使用this作为锁
/*
*路人假helloWorld
*/
class Window1 implements Runnable{
private int ticket = 100;
// Object obj = new Object();
@Override
public void run() {
while(true) {
synchronized(this ) {
if (ticket > 0) {
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + "卖票,票号为:" + ticket);
ticket--;
}else{
break;
}
}
}
}
}
public class WindowTest1 {
public static void main(String[] args) {
Window1 window1 = new Window1();
Thread t1 = new Thread(window1);
Thread t2 = new Thread(window1);
Thread t3 = new Thread(window1);
t1.setName("窗口1");
t2.setName("窗口2");
t3.setName("窗口3");
t1.start();
t2.start();
t3.start();
}
}
2.继承Thread类,使用的锁必须也是静态对象
class Window extends Thread{
//设置总票数100张
private static int ticket = 100;
static Object obj = new Object();
@Override
public void run() {
while (true) {
synchronized(obj){
if (ticket > 0){
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + "卖票,票号为:" + ticket);
ticket--;
}else {
break;
}
}
}
}
}
public class WindowTest {
public static void main(String[] args) {
Window t1 = new Window();
Window t2 = new Window();
Window t3 = new Window();
t1.setName("窗口1");
t2.setName("窗口2");
t3.setName("窗口3");
t1.start();
t2.start();
t3.start();
}
}
2.2 同步方法
关于同步方法的总结:
1.同步方法仍然涉及到同步监视器,只是不需要我们显式的声明。
2.
非静态的同步方法,同步监视器是: this ;
静态的同步方法,同步监视器是:当前类本身
1.实现Runnable接口
class Window2 implements Runnable{
private int ticket = 100;
@Override
public void run() {
while(true) {
show();
if (ticket <= 0){
break;
}
}
}
private synchronized void show(){
if (ticket > 0) {
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + "卖票,票号为:" + ticket);
ticket--;
}
}
}
public class WindowTest2 {
public static void main(String[] args) {
Window2 window2 = new Window2();
Thread t1 = new Thread(window2);
Thread t2 = new Thread(window2);
Thread t3 = new Thread(window2);
t1.setName("窗口1");
t2.setName("窗口2");
t3.setName("窗口3");
t1.start();
t2.start();
t3.start();
}
}
2.继承Thread类
class Window3 extends Thread{
//设置总票数100张
private static int ticket = 100;
@Override
public void run() {
while (true) {
show();
if (ticket <= 0){
break;
}
}
}
//必须是静态方法
private static synchronized void show(){
if (ticket > 0){
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + "卖票,票号为:" + ticket);
ticket--;
}
}
}
public class WindowTest3 {
public static void main(String[] args) {
Window3 t1 = new Window3();
Window3 t2 = new Window3();
Window3 t3 = new Window3();
t1.setName("窗口1");
t2.setName("窗口2");
t3.setName("窗口3");
t1.start();
t2.start();
t3.start();
}
}
3.3 Lock锁
创建ReentrantLock对象
/*
* 解决线程安全问题的方式三:Lock()锁 ---JDK5.0新增
*
* 1.面试题:synchronized 与 Lock的异同?
* 相同:二者都可以解决线程安全问题
* 不同:synchronized机制在执行完相应的同步代码后,自动释放同步监视器
* Lock需要手动的启动同步监视器(lock()),同时结束同步也需要手动的实现(unlock())
*
* 2.优先使用顺序:
* Lock --> 同步代码块(已经进入了方法体,分配了相应的资源) --> 同步方法(在方法体之外)
*
* 面试题:如何解决线程安全问题?有几种方式
*
* */
class LockWindow implements Runnable{
private int ticket = 100;
private ReentrantLock lock = new ReentrantLock();
@Override
public void run() {
while(true) {
try{
//调用lock()上锁
lock.lock();
if (ticket > 0) {
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + "卖票,票号为:" + ticket);
ticket--;
}else{
break;
}
}finally{
//调用unlock()解锁
lock.unlock();
}
}
}
}
public class LockWindowTest {
public static void main(String[] args) {
LockWindow window = new LockWindow();
Thread t1 = new Thread(window);
Thread t2 = new Thread(window);
Thread t3 = new Thread(window);
t1.setName("窗口1");
t2.setName("窗口2");
t3.setName("窗口3");
t1.start();
t2.start();
t3.start();
}
}
· 阿里巴巴 QwQ-32B真的超越了 DeepSeek R-1吗?
· 10年+ .NET Coder 心语 ── 封装的思维:从隐藏、稳定开始理解其本质意义
· 【译】Visual Studio 中新的强大生产力特性
· 【设计模式】告别冗长if-else语句:使用策略模式优化代码结构
· 字符编码:从基础到乱码解决