Java售票任务_多线程详细实现
题目回顾:铁道部发布了一个售票任务,要求销售1000张票,要求有3个窗口来进行销售,请编写多线程程序来模拟这个效果。
i. 窗口001正在销售第1000张票
ii. 窗口001正在销售第999张票
iii. 窗口002正在销售第998张票
iv. …
v. 窗口002正在销售第1张票
vi. 票已经销售完毕
一 、注意细节:
问题1:三个线程都卖了1000张票,一共卖了3000张票
原因:三个线程代表三个对象,就有三个成员变量(三个ticket)
解决方案:让成员变量ticket变成静态变量,因为静态变量是该类所有对象共享的变量
问题2:有些票卖了重票
原因:输出后切换到其他的线程,ticket变量没有–,所以造成了数据错误
解决方案:加锁,保证输出和ticket–运行完毕后,才能切换到其他线程
问题3:票数出现负数
原因:ticket零界点,3个线程都有可能进入
解决:在同步代码里再此判断
synchronized 同步锁、互斥锁:
注意:多个线程之间要想互斥,必须用同一把锁对象
同步代码块:
synchronized(锁对象){//上锁
…代码…
}//解锁
同步方法:
Lock锁:
二、 继承Thread接口实现
2.1 第一种解决方案:同步代码块
/*synchronized 同步锁、互斥锁:
* 注意:多个线程之间要想互斥,必须用同一把锁对象
* 同步代码块:
* synchronized(锁对象){//上锁
* ...代码...
* }//解锁
* /
public static void main(String[] args) {
myThread01 t1 = new myThread01("窗口一");
myThread01 t2 = new myThread01("窗口二");
myThread01 t3 = new myThread01("窗口三");
t1.start();
t2.start();
t3.start();
}
}
class myThread01 extends Thread{
private static int tecket = 1000;
private static Object obj= new Object();
public myThread01(String name) {
super(name);
}
@Override
public void run() {
while(tecket>0){
synchronized (obj) {
if(tecket>0){
System.out.println(Thread.currentThread().getName()+"正在销售第"+tecket+"张票");
tecket--;
}else if(tecket==0){
System.out.println(Thread.currentThread().getName()+"票已卖完");
}else{
System.out.println(Thread.currentThread().getName()+"票已卖完");
}
}
}
}
2.2 第二种解决方案:同步方法
public static void main(String[] args) {
/**
* 同步方法:
* 锁对象 -- this
* public synchronized void method01(){}
* 锁对象 -- 本类的字节码文件对象
* public synchronized static void method02(){}
*/
myThread01 t1 = new myThread01("窗口一");
myThread01 t2 = new myThread01("窗口二");
myThread01 t3 = new myThread01("窗口三");
t1.start();
t2.start();
t3.start();
}
}
class myThread02 extends Thread{
private static int tecket = 1000;
private static Object obj= new Object();
public myThread02(String name) {
super(name);
}
@Override
public void run() {
while(tecket>0){
method01();
}
}
public synchronized static void method01(){
synchronized (obj) {
if(tecket>0){
System.out.println(Thread.currentThread().getName()+"正在销售第"+tecket+"张票");
tecket--;
}else if(tecket==0){
System.out.println(Thread.currentThread().getName()+"票已卖完");
}else{
System.out.println(Thread.currentThread().getName()+"票已卖完");
}
}
}
2.3 第三种解决方案:lock锁
public class Thread_03 {
public static void main(String[] args) {
myThread01 t1 = new myThread01("窗口一");
myThread01 t2 = new myThread01("窗口二");
myThread01 t3 = new myThread01("窗口三");
t1.start();
t2.start();
t3.start();
}
}
/*
* * Lock锁:
* Lock lock = new ReentrantLock();
*/
class myThread03 extends Thread{
private static int tecket = 1000;
//创建lock锁对象
private static Lock lock = new ReentrantLock();
public myThread03(String name) {
super(name);
}
@Override
public void run() {
while(tecket>0){
lock.lock();//上锁
if(tecket>0){
System.out.println(Thread.currentThread().getName()+"正在销售第"+tecket+"张票");
tecket--;
}else if(tecket==0){
System.out.println(Thread.currentThread().getName()+"票已卖完");
}else{
System.out.println(Thread.currentThread().getName()+"票已卖完");
}
lock.unlock();//解锁
}
}
}
2.4 两种上锁方式对比:synchronized vs Lock(重要)
区别1:
* synchronized锁 会自动上锁、解锁
* Lock锁 必须手动上锁、解锁
* 区别2:
* synchronized JVM层面上的锁
* Lock API层面上的锁
* 区别3:
* Lock有读写锁
三、Runnable接口实现
3.1第一种方式实现:同步代码块
public class Runnable_01 {
public static void main(String[] args) {
myRunnable01 task = new myRunnable01();
Thread task1 = new Thread(task,"窗口一");
Thread task2 = new Thread(task,"窗口二");
Thread task3 = new Thread(task,"窗口三");
task1.start();
task2.start();
task3.start();
}
}
class myRunnable01 implements Runnable{
private int ticket = 1000;
private Object obj = new Object();
@Override
public void run() {
// TODO Auto-generated method stub
while(ticket > 0){
// synchronized("abc"){
// synchronized(Object.class){
// synchronized(obj){
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() + "票已卖完");
}
}
}
}
}
3.2 第二种方式实现:同步方法
p
public class Runnable_02 {
public static void main(String[] args) {
myRunnable02 task = new myRunnable02();
Thread task1 = new Thread(task,"窗口一");
Thread task2 = new Thread(task,"窗口二");
Thread task3 = new Thread(task,"窗口三");
task1.start();
task2.start();
task3.start();
}
}
class myRunnable02 implements Runnable{
private static int ticket = 1000;
private Object obj = new Object();
@Override
public void run() {
// TODO Auto-generated method stub
while(ticket > 0){
// synchronized("abc"){
// synchronized(Object.class){
// synchronized(obj){
methodR01();
}
}
public synchronized void methodR01(){
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() + "票已卖完");
}
}
}
3.3 第三种方式实现:lock锁
public class Runnable_03 {
public static void main(String[] args) {
myRunnable03 task = new myRunnable03();
Thread task1 = new Thread(task,"窗口一");
Thread task2 = new Thread(task,"窗口二");
Thread task3 = new Thread(task,"窗口三");
task1.start();
task2.start();
task3.start();
}
}
class myRunnable03 implements Runnable{
private int ticket = 1000;
private Lock lock = new ReentrantLock();
@Override
public void run() {
// TODO Auto-generated method stub
while(ticket > 0){
// synchronized("abc"){
// synchronized(Object.class){
// synchronized(obj){
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 {
public static void main(String[] args) {
//死锁
//尽可能不要锁嵌套
//线程1
new Thread(new Runnable() {
@Override
public void run() {
synchronized (KuaiZi.a) {
try {
Thread.sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
synchronized(KuaiZi.b){
System.out.println("哲学家1 吃饭了");
}
}
}
}).start();
//线程2
new Thread(new Runnable() {
@Override
public void run() {
synchronized (KuaiZi.b) {
try {
Thread.sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
synchronized(KuaiZi.a){
System.out.println("哲学家2 吃饭了");
}
}
}
}).start();
}
}
class KuaiZi{
public static Object a = new Object();
public static Object b = new Object();
}