Day18:多线程-火车站多窗口售票案例

本文探讨了进程与线程的概念,强调线程作为执行单位在效率上的优势。详细介绍了Java中实现多线程的两种方式,即继承Thread类和实现Runnable接口,并通过同步代码块、同步方法及ReentrantLock展示了多线程同步控制的应用。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

一、进程与线程

进程的特征:

  1. 每一个进程的内部数据和状态都是完全独立的;
  2. 创建并执行一个进程的系统开销是比较大的;
  3. 进程是程序的一次执行过程,是系统运行程序的基本单位。

线程的特征:

  1. 在Java中,程序通过流程控制来执行程序流。程序中单个顺序的流控制称为线程。
  2. 多线程指的是在单个进程中可以同时运行多个不同的线程,执行不同的任务。多线程意味着一个程序的多行语句可以看上去几乎同时运行。

线程和进程的主要差别体现在以下两个方面:

同样作为基本的执行单元,线程是划分得比进程更小的执行单位;

每个进程都有一段专用的内存区域。与此相反,线程却共享内存单元(包括代码和数据),通过共享的内存单元来实现数据交换、实时通信与必要的同步操作。

所谓的线程(Thread)是指程序的运行流程,“多线程”的机制是指可以同时运行多个程序块,使程序运行的效率变得更高。

 

实现多线程的两种方式:

通过继承Thread实现多线程     重写run方法

通过实现Runnable接口实现多线程    重写run方法

一个类只能有一个父类,所以在Java中如果一个类继承了某一个类,同时又想采用多线程技术的时候,就不能用Thread类产生线程,因为Java不允许多继承,这时要用Runnable接口来创建线程。

 

 

栗子:

/**
		 * 铁道部发布了一个售票任务,要求销售1000张票,要求有3个窗口来进行销售,请编写多线程程序来模拟这个效果
				窗口001正在销售第1000张票
				窗口001正在销售第999张票
				窗口002正在销售第998张票
				。。。
				窗口002正在销售第1张票
				票已经销售完毕

			问题1:三个窗口各买1000张票
			原因:三个线程使用了三个任务,就有三个ticket的变量
			解决:	
				1.三个线程去执行同一个任务
				2.把ticket修饰成成员变量

			问题2:有些票卖了重票
			原因:输出票数和票的自减不是同一时间执行
			解决:输出票数和票的自减必须执行完毕后才能让别的线程抢资源--加锁

			锁:同步锁/互斥锁 --- synchronized
			注意:多个线程之间,必须是同一把锁对象才能锁的住
			同步代码块:
				synchronized(锁对象){//上锁
					上锁后的代码块
				}//解锁

			问题3:卖了负票
			原因:ticket在零界点的时候,三个线程进入到循环后,上锁自减

		 */

任务类-同步代码块:

public class Test01 {
	public static void main(String[] args) {
		Task task = new Task();
		new Thread(task,"窗口1").start();
		new Thread(task,"窗口2").start();
		new Thread(task,"窗口3").start();

	}
}
class Task implements Runnable{
	private int ticket=1000;
	@Override
	public void run() {
		while(ticket>0) {
			synchronized (this) {
				if(ticket>0) {
					System.out.println(Thread.currentThread().getName()+"正在销售第"+ticket+"张票");
					ticket--;
					if(ticket==0) {
						System.out.println(Thread.currentThread().getName()+"票已售完");
					}
				}else {
					System.out.println(Thread.currentThread().getName()+"票已售完");

				}
			}
		}

	}

}

任务类-同步方法

public class Test01 {
	public static void main(String[] args) {
		Task task = new Task();
		new Thread(task,"窗口1").start();
		new Thread(task,"窗口2").start();
		new Thread(task,"窗口3").start();

	}
}
class Task implements Runnable{
	private static int ticket=1000;
	@Override
	public void run() {
		while(ticket>0) {
			this.method1();
//			Task.method2();
		}

	}
	//同步方法:锁对象this
	public synchronized void method1() {
		if(ticket>0) {
			System.out.println(Thread.currentThread().getName()+"正在销售第"+ticket+"张票");
			ticket--;
			if(ticket==0) {
				System.out.println(Thread.currentThread().getName()+"票已售完");
			}
		}else {
			System.out.println(Thread.currentThread().getName()+"票已售完");

		}
	}
	//同步方法:锁对象Task.class
	public static synchronized void method2() {
		if(ticket>0) {
			System.out.println(Thread.currentThread().getName()+"正在销售第"+ticket+"张票");
			ticket--;
			if(ticket==0) {
				System.out.println(Thread.currentThread().getName()+"票已售完");
			}
		}else {
			System.out.println(Thread.currentThread().getName()+"票已售完");

		}
	}


}

任务类-ReentrantLock

public class Test01 {
	public static void main(String[] args) {
		Task task = new Task();
		new Thread(task,"窗口1").start();
		new Thread(task,"窗口2").start();
		new Thread(task,"窗口3").start();

	}
}
class Task implements Runnable{
	private static int ticket=1000;
	private static Lock lock = new ReentrantLock();
	@Override
	public void run() {
		while(ticket>0) {
			lock.lock();
			if(ticket>0) {
				System.out.println(Thread.currentThread().getName()+"正在销售第"+ticket+"张票");
				ticket--;
				if(ticket==0) {
					System.out.println(Thread.currentThread().getName()+"票已售完");
				}
			}else {
				System.out.println(Thread.currentThread().getName()+"票已售完");

			}
			lock.unlock();
		}

	}
}

线程类-同步代码块

public class Test01 {
	/**
	 * 
	 * synchronized同步代码块
	 */
	public static void main(String[] args) {
		//创建线程
		new MyThread("窗口1").start();;
		new MyThread("窗口2").start();;
		new MyThread("窗口3").start();;
		
		
		
	}
}
//自定义线程类
class MyThread extends Thread{
	private int ticket = 1000;
	public MyThread(String name) {
		super(name);
	}


	//重写run方法
	@Override
	public void run() {
		while(ticket>0) {
			synchronized (this) {
				if(ticket>0) {
					System.out.println(Thread.currentThread().getName()+"正在销售第"+ticket+"张票");
					ticket--;
					if(ticket==0) {
						System.out.println(Thread.currentThread().getName()+"票已售完");
					}
				}else {
					System.out.println(Thread.currentThread().getName()+"票已售完");
				}
					
			}
		}
	}
	
	
}

线程类-同步方法

public class Test01 {
	/**
	 * 
	 * synchronized同步方法
	 */
	public static void main(String[] args) {

		//创建线程
		new MyThread("窗口1").start();;
		new MyThread("窗口2").start();;
		new MyThread("窗口3").start();;
	}
}
//自定义线程类
class MyThread extends Thread{
	private static int ticket = 1000;
	public MyThread(String name) {
		super(name);
	}


	//重写run方法
	/**
	 * 为什么不把while也锁在里面?
	 * 假设while在锁内,线程都启动后,线程1率先抢到资源,那么t1就会一直执行while循环,直至结束
	 */
	@Override
	public void run() {
		while(ticket>0) {
			method();
		}
	}
	//封装方法
	public static synchronized void method() {

		if(ticket>0) {
			System.out.println(Thread.currentThread().getName()+"正在销售第"+ticket+"张票");
			ticket--;
			if(ticket==0) {
				System.out.println(Thread.currentThread().getName()+"票已售完");
			}
		}else {
			System.out.println(Thread.currentThread().getName()+"票已售完");


		}
	}
}

 

线程类-ReentrantLock

public class Test01 {
	/**
	 * ReetrantLock
	 * lock.lock()
	 * lock.unlock()
	 */
	public static void main(String[] args) {

		//创建线程
		new MyThread("窗口1").start();;
		new MyThread("窗口2").start();;
		new MyThread("窗口3").start();;
	}
}
//自定义线程类
class MyThread extends Thread{
	private int ticket = 1000;
	private static Lock lock = new ReentrantLock();
	public MyThread(String name) {
		super(name);
	}


	//重写run方法
	@Override
	public void run() {
		while(ticket>0) {
			lock.lock();
			if(ticket>0) {
				System.out.println(Thread.currentThread().getName()+"正在销售第"+ticket+"张票");
				ticket--;
				if(ticket==0) {
					System.out.println(Thread.currentThread().getName()+"票已售完");
				}
			}else {
				System.out.println(Thread.currentThread().getName()+"票已售完");
			}
			lock.unlock();
		}
	}
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值