Java多线程(四) Thread和Runnable之区别(售票系统)

时间:2022-03-25 17:34:33

Thread和Runnable之区别(售票系统)

两种方式有什么不同,利用Runnable可以实现资源共享:

一、售票系统用Thread进行实现如下:

public class TicketThread extends Thread {
private int ticket = 5;// 总共5张票


@Override
public void run() {
while (true)
if (ticket > 0)
System.out.println(Thread.currentThread().getName() + ":正在卖第" + ticket-- + "张票 ... ... ");
}


public static void main(String[] args) {
// 创建3个线程
TicketThread tt1 = new TicketThread();
TicketThread tt2 = new TicketThread();
TicketThread tt3 = new TicketThread();
// 启动线程
tt1.start();
tt2.start();
tt3.start();
}

}


运行结果如下:

Thread-2:正在卖第5张票 ... ... 
Thread-2:正在卖第4张票 ... ... 
Thread-2:正在卖第3张票 ... ... 
Thread-2:正在卖第2张票 ... ... 
Thread-2:正在卖第1张票 ... ... 
Thread-0:正在卖第5张票 ... ... 
Thread-0:正在卖第4张票 ... ... 
Thread-0:正在卖第3张票 ... ... 
Thread-0:正在卖第2张票 ... ... 
Thread-0:正在卖第1张票 ... ... 
Thread-1:正在卖第5张票 ... ... 
Thread-1:正在卖第4张票 ... ... 
Thread-1:正在卖第3张票 ... ... 
Thread-1:正在卖第2张票 ... ... 
Thread-1:正在卖第1张票 ... ... 

一共5张票,实际执行结果却是卖了15张票。从中可以看出使用Thread不能够实现数据共享的效果。


二、售票系统用Runnable进行实现如下:

public class TicketRunnable implements Runnable {
private int ticket = 5;// 总共5张票


@Override
public void run() {
while (true)
if (ticket > 0)
System.out.println(Thread.currentThread().getName() + ":正在卖第" + ticket-- + "张票 ... ... ");
}


public static void main(String[] args) {
// 利用实例化一个Runnable对象,实现共享
TicketRunnable tr = new TicketRunnable();
// 创建3个线程
Thread tt1 = new Thread(tr, "1号窗户");
Thread tt2 = new Thread(tr, "2号窗户");
Thread tt3 = new Thread(tr, "3号窗户");
// 启动线程
tt1.start();
tt2.start();
tt3.start();
}
}

运行结果如下:

1号窗户:正在卖第5张票 ... ... 
3号窗户:正在卖第3张票 ... ... 
2号窗户:正在卖第4张票 ... ... 
3号窗户:正在卖第1张票 ... ... 
1号窗户:正在卖第2张票 ... ... 

一共5张票,实际执行结果也是卖了5张票。从中可以看出使用Runnable能够实现数据共享的效果。

利用实例化一个Runnable对象,实现共享。


三、通过只实例化一个Runnable对象来进行共享资源。

需求:主线程和子线程都是并发执行的,也就是当子线程在执行的过程中,主线程也在往下执行。主线程需要所有子线程返回执行结果才能继续执行。

我们利用一个CountDownLatch来实现。

CountDownLatch,一个同步辅助类,在完成一组正在其他线程中执行的操作之前,它允许一个或多个线程一直等待。

主要方法

public CountDownLatch(int count);

public void countDown();

public void await() throws  InterruptedException

构造方法参数指定了计数的次数

countDown方法,当前线程调用此方法,则计数减一

awaint方法,调用此方法会一直阻塞当前线程,直到计时器的值为0

实例如下:

import java.util.concurrent.CountDownLatch;


public class MyRunnableReturn implements Runnable {
private CountDownLatch threadsSingal;


public MyRunnableReturn(CountDownLatch threadsSingal) {
super();
this.threadsSingal = threadsSingal;
}


public void run() {
System.out.println(Thread.currentThread().getName() + "--开始");
System.out.println(Thread.currentThread().getName() + "--结束");
threadsSingal.countDown();// 线程减1
}


public static void main(String[] agrs) {
System.out.println("Main --开始");
CountDownLatch threadsSingal = new CountDownLatch(3);
MyRunnableReturn myRunnable = new MyRunnableReturn(threadsSingal);
new Thread(myRunnable, "thread1").start();
new Thread(myRunnable, "thread2").start();
new Thread(myRunnable, "thread3").start();
try {
threadsSingal.await();// 等待所有子线程执行完
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("Main --结束");
}
}


运行结果如下:

Main --开始
thread1--开始
thread1--结束
thread3--开始
thread3--结束
thread2--开始
thread2--结束
Main --结束

综上实例可以看出,达到了需求的效果。先执行所有子线程,再运行主线程。