【Java基础】多线程实例

您所在的位置:网站首页 深圳汽车售票系统 【Java基础】多线程实例

【Java基础】多线程实例

2023-09-27 06:38| 来源: 网络整理| 查看: 265

本一节作为多线程、线程通信、线程安全和线程池的举例和补充,旨在说明多线程问题中的线程安全问题的解决。

问题描述

假设售票厅有3个窗口可以售卖某次列车的最后100张车票,这三个窗口可以看做三个线程,100张车票可以看做三个线程共享的资源,仔细分析,这个问题中存在线程安全问题。

一.直接实现售票

1.继承Thread类,重run()方法

/** * 三个窗口买票:共售100张票 * 存在线程安全的问题 * @author wds * @date 2021-11-15-20:30 */ public class ThreadTest04 { public static void main(String[] args) { Thread04 thread04 = new Thread04(); Thread thread = new Thread(thread04, "窗口1"); Thread thread1 = new Thread(thread04, "窗口2"); Thread thread2 = new Thread(thread04, "窗口3"); thread.start(); thread1.start(); thread2.start(); } } class Thread04 extends Thread{ private static int ticket = 100; //静态数据共享 @Override public void run() { while (true){ if(ticket>0){ try { Thread.sleep(100); //模拟售票需要的时间 } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(Thread.currentThread().getName()+"正在售票,票号为:"+ticket); ticket--; }else { break; } } } }

2…实现Runnable接口,重写run()方法

/** * 例:三个窗口共售100张票 * 存在线程安全的问题 * * @author wds * @date 2021-11-15-20:18 */ public class ThreadTest03 { public static void main(String[] args) { Thread03 thread03 = new Thread03(); Thread thread = new Thread(thread03,"窗口1"); Thread thread1 = new Thread(thread03,"窗口2"); Thread thread2 = new Thread(thread03,"窗口3"); thread.start(); thread1.start(); thread2.start(); } } class Thread03 implements Runnable{ private static int ticket = 100; //静态数据共享 @Override public void run() { while(true){ if(ticket>0){ try { Thread.sleep(100); //模拟售票需要的时间 } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(Thread.currentThread().getName()+"正在售票,票号为:"+ticket); ticket--; } } } }

在这里插入图片描述

以上两种方式存在线程安全问题,如错票,重票,这在现实生活中是绝对不允许出现的。接下来考虑多线程的安全问题,对以上两种方式进行改写。

二.改进后的方法

1.继承Thread类,重run()方法 方式一:使用synchronized同步代码块解决继承Thread方式解决售票问题中的线程安全问题

/** * 方式一:使用synchronized同步代码块解决继承Thread方式解决售票问题中的线程安全问题 * * @author wds * @date 2021-11-16-9:53 */ public class ThreadTest01 { public static void main(String[] args) { Thread01 thread01 = new Thread01(); Thread01 thread02 = new Thread01(); Thread01 thread03 = new Thread01(); thread01.setName("窗口1"); thread02.setName("窗口2"); thread03.setName("窗口3"); thread01.start(); thread02.start(); thread03.start(); } } class Thread01 extends Thread { private static int ticket = 100; //静态常量数据共享 private 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--; } } } } }

方式二:使用synchronized同步方法解决继承Thread方式解决售票问题中的线程安全问题

/** * 方式二:使用synchronized同步方法解决继承Thread方式解决售票问题中的线程安全问题 * @author wds * @date 2021-11-16-11:20 */ public class ThreadTest03 { public static void main(String[] args) { Thread03 t1 = new Thread03(); Thread03 t2 = new Thread03(); Thread03 t3 = new Thread03(); t1.setName("窗口1"); t2.setName("窗口2"); t3.setName("窗口3"); t1.start(); t2.start(); t3.start(); } } class Thread03 extends Thread { private static int ticket = 100; //静态常量数据共享 @Override public void run() { while (true) { show(); } } public static synchronized void show() { //同步方法 if (ticket > 0) { try { Thread.sleep(100); //模拟售票所需要的时间 } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(Thread.currentThread().getName() + "正在售票,票号为" + ticket); ticket--; } } }

方式三:使用Lock锁机制解决继承Thread方式解决售票问题中的线程安全问题

import java.util.concurrent.locks.ReentrantLock; /** * 方式三:使用Lock锁机制解决继承Thread方式解决售票问题中的线程安全问题 * @author wds * @date 2021-11-16-20:36 */ public class ThreadTest06 { public static void main(String[] args) { Thread6 t1 = new Thread6(); Thread6 t2 = new Thread6(); Thread6 t3 = new Thread6(); t1.setName("窗口1"); t2.setName("窗口2"); t3.setName("窗口3"); t1.start(); t2.start(); t3.start(); } } //单例模式:继承方式使用的必须是同一个锁才可以,我们选择使用饿汉式单例模式 class LockInstance{ private LockInstance(){} private static ReentrantLock instance = new ReentrantLock(); public static ReentrantLock getInstance() { return instance; } } class Thread6 extends Thread{ private static int ticket = 100; ReentrantLock lock; { lock = LockInstance.getInstance(); } @Override public void run() { while(true){ try{ lock.lock(); if(ticket>0){ try { Thread.sleep(100); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(Thread.currentThread().getName()+"正在售票,票号为"+ticket); ticket--; } }finally { lock.unlock(); } } } } //本方法大家运行时一定要多试几次,程序逻辑很严密,不一定一次就会出结果

2…实现Runnable接口,重写run()方法 方式一:使用synchronized同步代码块解决实现Runnable接口方式解决售票问题中的线程安全问题

/** * 方式一:使用synchronized同步代码块解决实现Runnable接口方式解决售票问题中的线程安全问题 * @author wds * @date 2021-11-16-10:09 */ public class ThreadTest02 { public static void main(String[] args) { Thread02 thread02 = new Thread02(); Thread t1 = new Thread(thread02, "窗口1"); Thread t2 = new Thread(thread02, "窗口2"); Thread t3 = new Thread(thread02, "窗口3"); t1.start(); t2.start(); t3.start(); } } class Thread02 implements Runnable { private static int ticket = 100; //静态常量数据共享 //private static Object obj = new Object(); @Override public void run() { while (true) { //方式1:对象做为监视器 //synchronized (obj){ //同步代码块 //方式2:this关键字作为监视器 //synchronized (this){ //方式3:类名.class作为监视器 synchronized (Thread02.class) { if (ticket > 0) { try { Thread.sleep(100); //模拟售票花费的时间 } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(Thread.currentThread().getName() + "正在售票,票号为" + ticket); ticket--; } } } } }

方式二:使用synchronized同步方法解决实现接口Runnable方式解决售票问题中的线程安全问题

/** * 方式二:使用synchronized同步方法解决实现接口Runnable方式解决售票问题中的线程安全问题 * @author wds * @date 2021-11-16-11:31 */ public class ThreadTest04 { public static void main(String[] args) { Thread04 thread04 = new Thread04(); Thread t1 = new Thread(thread04, "窗口1"); Thread t2 = new Thread(thread04, "窗口2"); Thread t3 = new Thread(thread04, "窗口3"); t1.start(); t2.start(); t3.start(); } } class Thread04 implements Runnable{ private static int ticket = 100; //静态常量共享数据 @Override public void run() { while(true){ show(); } } public synchronized static void show(){ //同步方法 if(ticket>0){ try { Thread.sleep(100); //模拟售票过程需要的时间 } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(Thread.currentThread().getName()+"正在售票,票号为"+ticket); ticket--; } } }

方式三:使用Lock锁机制解决实现Runnable接口方式解决售票问题中的线程安全问题

/** * 方式三:使用Lock锁机制解决实现Runnable接口方式解决售票问题中的线程安全问题 * @author wds * @date 2021-11-16-15:22 */ public class ThreadTest05 { public static void main(String[] args) { Thread05 thread05 = new Thread05(); Thread t1 = new Thread(thread05, "窗口1"); Thread t2 = new Thread(thread05, "窗口2"); Thread t3 = new Thread(thread05, "窗口3"); t1.start(); t2.start(); t3.start(); } } class Thread05 implements Runnable{ private static int ticket = 100; //1.实例化ReentrantLock private ReentrantLock lock = new ReentrantLock(); @Override public void run() { while(true){ try{ //2.调用lock()锁定 lock.lock(); if(ticket>0){ try { Thread.sleep(100); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(Thread.currentThread().getName()+"正在售票,票号为:"+ticket); ticket--; } }finally { //3.调用unlock()解锁 lock.unlock(); } } } }

在这里插入图片描述 注意: 多线程运行时各个线程未指定优先级,都是自己抢占cpu的执行权,具体的执行结果根据自己的运行结果而定,不一定和上面的截图一致。



【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3