深圳网站建设 利科技,湖北民族建设集团网站,全国免费的分类信息网,我想在阿里巴巴上给别人做网站文章目录1.概述2.实现方案一#xff1a;继承Thread2.1 代码实现2.2 代码分析3.实现方案二#xff1a;实现Runnable接口3.1 代码实现3.2 代码分析4.实现方案三#xff1a;构建线程池4.1 代码实现4.2 代码分析1.概述
接下来我们通过一个售票案例的实际操作来深入理解线程的相… 文章目录1.概述2.实现方案一继承Thread2.1 代码实现2.2 代码分析3.实现方案二实现Runnable接口3.1 代码实现3.2 代码分析4.实现方案三构建线程池4.1 代码实现4.2 代码分析1.概述
接下来我们通过一个售票案例的实际操作来深入理解线程的相关应用
需求设计4个售票窗口总计售票100张使用多线程的方式进行售卖当票售完后停止售卖在控制台打印具体为哪个线程售卖了第多少张票
2.实现方案一继承Thread
首先我们通过简单的方法——继承Thread类来实现这一功能
2.1 代码实现
package partFour;
/*设计多线程编程模型4个窗口购机售票100张* 本方案使用多线程编程方案1继承Thread类的方式来完成*/
public class TestThreat {public static void main(String[] args) {//5.创建多个线程对象TicketsThread t1 new TicketsThread();TicketsThread t2 new TicketsThread();TicketsThread t3 new TicketsThread();TicketsThread t4 new TicketsThread();//6.以多线程的方式启动t1.start();t2.start();t3.start();t4.start();}
}
//1.自定义多线程售票类继承Thread
class TicketsThread extends Thread{//3.定义变量保存要卖的票数,需要设置静态不然4个线程对象每个线程对象都会有100张票/*4个线程对象每个线程对象售票400张原因是创建了4次对象各自操作各自的成员变量* 解决让所有对象共享同一个数据票数需要设置为静态*/static int tickets 100;//2.重新run方法Overridepublic void run(){//4.1循环卖票使用while循环方便后续演示容易出错的位置while (true){//7.让每个线程经历休眠增加线程状态切换频率与出错的概率//问题1产生重卖的现象同一张票卖给多人//问题2产生了超卖的现象超出了规定的票数100出现了0-1-2try {Thread.sleep(10);//让当前线程休眠10ms} catch (InterruptedException e) {e.printStackTrace();}//4.2打印当前正在卖票的线程名称并且票数-1System.out.println(getName()tickets--);//4.3做判断如果没有票了就退出死循环if (tickets0) break;//注意死循环一定要设置出口}}
}2.2 代码分析
每次创建线程对象都会生成一个tickets变量值是100创建4次对象就生成了400张票了。不符合需求怎么解决呢 能不能把tickets变量在每个对象间共享就保证多少个对象都是卖这100张票。 解决方案: 用静态修饰产生超卖0 张 、-1张、-2张。产生重卖同一张票卖给多人。多线程安全问题是如何出现的常见情况是由于线程的随机性访问延迟。以后如何判断程序有没有线程安全问题 在多线程程序中 有共享数据 多条语句操作共享数据就一定会有线程的并发安全问题就一定考虑如何避免或解决这个问题 在目前我们只能考虑使用同步锁解决
3.实现方案二实现Runnable接口
接下来我们将使用更复杂一点的Runnable接口来实现此功能
3.1 代码实现
package partFour;
/*需求设计多线程编程模型4个窗口共计售票100张* 本方案使用多线程编程方案2实现Runnable接口的方式来完成*/
public class TestRunnable {public static void main(String[] args) {//5.创建Runnable接口的实现类对象作为目标业务对象TicketsRunnable target new TicketsRunnable();//6.创建多个Thread类线程对象并将target业务交给多个线程对象来处理Thread t1 new Thread(target);Thread t2 new Thread(target);Thread t3 new Thread(target);Thread t4 new Thread(target);//7.以多线程的方式启动多个线程对象t1.start();t2.start();t3.start();t4.start();}
}//1.自定义多线程类实现Runnable接口
class TicketsRunnable implements Runnable{//3.定义一个成员变量用来保存票数100/*由于自定义类对象只创建了一次所以票数被所有线程对象Thread共享* 不需要添加static只卖了100张票不会卖400次*/int tickets 100;//2.添加接口中未实现的方法方法里是我们的业务Overridepublic void run(){//4.1循环卖票while (true){//8.让每个线程经历休眠增加线程状态切换频率与出错的概率//问题1产生重卖的现象同一张票卖给多人//问题2产生了超卖的现象超出了规定的票数100出现了0-1-2try {Thread.sleep(10);//让当前线程休眠10ms} catch (InterruptedException e) {e.printStackTrace();}//4.2打印当前正在售票的线程名称 票数-1System.out.println(Thread.currentThread().getName()tickets--);//4.3设置死循环的出口没票了就停止卖票if(tickets0)break;}}
}3.2 代码分析
实现Runnable接口中因为只创建了一个对象所以并不会生成多个tickets变量的值所以此处我们不需要使用静态来修饰变量同样产生超卖0 张 、-1张、-2张。同样产生重卖同一张票卖给多人。同样产生线程的并发安全问题
4.实现方案三构建线程池
如果在程序中创建大量的生命周期很短的线程这会对性能产生比较大的影响构建一个新的线程还算是一个比较大的开销
此时我们可以利用线程池很好的去解决这个问题这样我们就不必将每个任务都映射到一个单独的线程上了。
线程池中会包含很多准备运行的线程为线程池提供一个Runnable就会有一个线程调用run方法当run方法执行完毕后线程并不会死亡而是继续在池中等待下一个请求的调用。
我们通常使用Executors用来辅助创建线程池的工具类常用的方法是newFixedThreadPoo(int)这个方法可以帮我们创建指定数目线程的线程池
4.1 代码实现
package partFour;import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;/* 本类用于回顾多线程售票案例2*/
public class TestRunnablevPool {public static void main(String[] args) {//1.创建实现类也就是目标业务对象TicktRunnable2 target new TicktRunnable2();//2.使用Excutors创建最多包含5个线程的线程池--ExcutorService/*Executors是用来辅助创建线程池的工具类* 常用的方法是newFixedThreadPoo(int)这个方法可以帮我们创建指定书目线程的线程池*/ExecutorService pool Executors.newFixedThreadPool(5);//3.使用循环启动线程for(int i0; i5; i){/*execute让线程池中的线程来执行业务* 每次调用这个方法都会将一个线程加到就绪队列中* 这个方法的参数就是我们要执行的具体业务也就是目标业务类对象target*/pool.execute(target);}}
}//1.创建接口实现类作为目标业务量
class TicktRunnable2 implements Runnable{//3.1定义票数int tickets 100;//8.注意在外部添加一个唯一的对象Object o new Object();//2.添加父接口中未实现的抽象方法里面是业务Overridepublic void run() {//3.2循环卖票while (true) {if (tickets0)//7.为了增加线程状态切换概率与出错频率在售票前休眠10毫秒try {Thread.sleep(10);} catch (InterruptedException e) {e.printStackTrace();}System.out.println(窗口 Thread.currentThread().getName() 售票 tickets--);if (tickets 0) break;}}
}
4.2 代码分析
通过构建线程池可以很好的解决资源浪费的问题虽然使用了双重校验但还是存在超卖重卖的问题