本文主要是介绍Thread线程二 多线程服务 卖票服务,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!
卖票服务
引入问题:
有一百张票,分为三个从窗口
测试类
public static void main(String[] args) {RunnableImpl run=new RunnableImpl();Thread t0=new Thread(run);Thread t1=new Thread(run);Thread t2=new Thread(run);//调用start,开启多线程t0.start();t1.start();t2.start();
}
第一次代码:
只要有票就售出,三个窗口为三个线程,同时执行
public class RunnableImpl implements Runnable {
private int ticket=100;
@Override
public void run() {while (true){if(ticket>0){System.out.println(Thread.currentThread().getName()+"正在卖第"+ticket+"张票!");ticket--;}}}
}
效果:
Thread-2正在卖第100张票!
Thread-2正在卖第99张票!
Thread-2正在卖第98张票!
Thread-1正在卖第100张票!
Thread-1正在卖第96张票!
Thread-2正在卖第97张票!
Thread-2正在卖第94张票!
Thread-2正在卖第93张票!
Thread-0正在卖第100张票!
原因:线程争夺资源,同时进入cpu中,系统没有调休实现,所以出现票重复 卖出的情况。
改进算法:
卖票的时间每个改为10ms,意味着线程休眠10ms。使得资源得以缓冲
static void sleep(long millis)
使当前正在执行的线程以指定的毫秒数暂停(暂时停止执行),具体取决于系统定时器和调度程序的精度和准确性。
public class RunnableImpl implements Runnable {
private int ticket=100;
@Override
public void run() {while (true){try {Thread.sleep(10);} catch (InterruptedException e) {e.printStackTrace();}if(ticket>0){System.out.println(Thread.currentThread().getName()+"正在卖第"+ticket+"张票!");ticket--;}}}
}
效果:
Thread-0正在卖第100张票!
Thread-1正在卖第100张票!
Thread-2正在卖第100张票!
Thread-0正在卖第97张票!
Thread-1正在卖第97张票!
Thread-2正在卖第95张票!
原因:还是因为争夺cpu,同时进入,改进并没有找到根本原因!
使用synchronized(锁对象)同步代码块
synchronized(锁对象)
{可能会出现线程安全问题的代码(访问了共享数据的代码)}
注意:
-
1.通过代码块中的锁对象,可以使用任意的对象
-
2.但是必须保证多个线程使用的锁对象是同一个
-
3.锁对象作用:
-
把同步代码块锁住,只让一个线程在同步代码块中执行
public class RunnableImpl implements Runnable {private int ticket=100;//创建一个锁对象 Object obj=new Object(); @Overridepublic void run() {while (true){//同步代码块synchronized (obj)//也可以synchronized(this){try {Thread.sleep(10);} catch (InterruptedException e) {e.printStackTrace();}if(ticket>0){System.out.println(Thread.currentThread().getName()+"正在卖第"+ticket+"张票!");ticket--;}}}}}
效果:
Thread-0正在卖第100张票!
Thread-0正在卖第99张票!
Thread-0正在卖第98张票!
Thread-0正在卖第97张票!
Thread-0正在卖第96张票!
Thread-0正在卖第95张票!
Thread-0正在卖第94张票!
Thread-0正在卖第93张票!
原理:
使用同步方法
锁对象是this
使用步骤:
1.把访问了共享数据代码抽取出来,放入到一个方法中
2.在方法上添加synchronized
代码:
public class RunnableImpl implements Runnable {
private int ticket=100;
//创建一个锁对象
@Override
public void run() {while (true){//同步代码块payTicket();}}
public synchronized void payTicket()
{if(ticket>0){try {Thread.sleep(10);} catch (InterruptedException e) {e.printStackTrace();}System.out.println(Thread.currentThread().getName()+"正在卖第"+ticket+"张票!");ticket--;}
}
}
效果:
Thread-0正在卖第100张票!
Thread-0正在卖第99张票!
Thread-0正在卖第98张票!
Thread-0正在卖第97张票!
Thread-0正在卖第96张票!
Thread-0正在卖第95张票!
Thread-0正在卖第94张票!
Thread-0正在卖第93张票!
设置票为私有静态,则同步方法也是静态方法
静态的同步方法
锁对象是静态方法的锁对象是本类的class属性–>class文件对象(反射)
代码:
public class RunnableImpl implements Runnable {
private static int ticket=100;//创建一个锁对象
@Override
public void run() {while (true){//同步代码块payTicket();}}
/*使用静态方法解决同步问题*/
public static synchronized void payTicket()
{//去掉synchronized 关键字换上//synchronized(RunnableImpl.class){}if(ticket>0){try {Thread.sleep(10);} catch (InterruptedException e) {e.printStackTrace();}System.out.println(Thread.currentThread().getName()+"正在卖第"+ticket+"张票!");ticket--;}
}
}
这篇关于Thread线程二 多线程服务 卖票服务的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!