多线程之卖票程序
来源:互联网 发布:网络安全法全文 编辑:程序博客网 时间:2024/05/17 02:14
总共有100张票,两个站点同时出售。
程序1:
class MyThread implements Runnable{/*一百张票*/private int tickets = 100;@Overridepublic void run() {while (true){if (tickets > 0){System.out.printf("%s线程正在卖出第%d张票!\n",Thread.currentThread().getName(),tickets);tickets --;} else {break;}}}}public class ThreadSynTest {public static void main(String[] args) {/*第一个站点卖票*/MyThread t1 = new MyThread();new Thread(t1).start();/*第二个站点卖票*/MyThread t2 = new MyThread();new Thread(t2).start();}}显示结果:
从结果可以发现,这两个线程卖的是各自的100张票,显然是不对的。
程序二:我们把票数的变量改为静态的。
/** * 把票数的变量改为静态的 * @author Liao * */class MyThread implements Runnable{/*一百张票*/private static int tickets = 100;@Overridepublic void run() {while (true){if (tickets > 0){System.out.printf("%s线程正在卖出第%d张票!\n",Thread.currentThread().getName(),tickets);tickets --;} else {break;}}}}public class ThreadSynTest {public static void main(String[] args) {/*第一个站点卖票*/MyThread t1 = new MyThread();new Thread(t1).start();/*第二个站点卖票*/MyThread t2 = new MyThread();new Thread(t2).start();}}显示结果:
从图中可以看出,还是有问题!
产生上述结果的原因是程序在执行过程中线程是来回自由切换的,有可能第一个线程刚卖出票,数量还没来得及减一,就跳到了线程二。
从上面的分析来看,要想使得多个线程操作一个资源,我们必须使用一个互斥的手段来限制多个线程同时操作一个资源。
Java提供了Synchronized关键字来确保线程的同步。
synchronized可以用来修饰一个方法和一个方法内部的某个代码块。
1:修饰代码块:
synchronized(a){//同步代码块}
上述代码表示当前线程霸占a对象,并执行代码块中的内容,其他线程无法执行代码块中的内容,只有当前线程执行完成之后,释放了对a对象的霸占,其他线程才有可能执行代码块中的内容。
总而言之:synchronized的功能就是一个线程正在操作某资源的时候,将不允许其他线程操作该资源,即一次只允许一个线程处理该资源。
2:修饰方法:
synchronized修饰一个方法时,实际霸占的是该方法的this指针所指向的对象,就是正在调用该方法的对象
我们先来看几种有问题的程序:
class MyThread1 implements Runnable {/* 一百张票 */private static int tickets = 100;@Overridepublic void run() {synchronized (this) {while (true) {/* 不能放在外面:放在外面的话就表示一个线程跳进来之后,就互斥了,其他线程就跳不进来,导致只有一个线程在卖票 */if (tickets > 0) {System.out.printf("%s线程正在卖出第%d张票!\n", Thread.currentThread().getName(), tickets);tickets--;} else {break;}}}}}public class ThreadSynTest3 {public static void main(String[] args) {MyThread1 t = new MyThread1();/* 第一个站点卖票 */Thread thread1 = new Thread(t);thread1.start();/* 第二个站点卖票 */Thread thread2 = new Thread(t);thread2.start();}}
程序输出的结果:
结果显示,永远都是一个线程在卖票;我觉得导致这个问题的原因是线程的启动也是调用run()方法,程序中run()方法的第一句代码就是执行synchronized这就导致了一开始就锁定了某个线程。直到这个线程把票都卖完了。
示例代码二:
class A implements Runnable{private int tickets = 100;@Overridepublic synchronized void run() {while (true){if (tickets > 0){System.out.printf("%s线程正在卖出第%d张票!\n",Thread.currentThread().getName(),tickets);tickets --;} else {break;}}}}public class ThreadTest2 {public static void main(String[] args) {A a = new A();new Thread(a).start();new Thread(a).start();}}
这个程序的问题和上一个程序是类似的,程序一执行,就锁定了某个线程导致了这个线程把票全卖完了。
正确程序:
class MyThread implements Runnable {/* 一百张票,注意这里要把变量定义为静态的 */private static int tickets = 100;@Overridepublic void run() {while (true) {/*不能放在外面:放在外面的话就表示一个线程跳进来之后,就互斥了,其他线程就跳不进来,导致只有一个线程在卖票*/synchronized (this) {if (tickets > 0) {System.out.printf("%s线程正在卖出第%d张票!\n", Thread.currentThread().getName(), tickets);tickets--;} else {break;}}}}}public class ThreadSynTest {public static void main(String[] args) {MyThread t = new MyThread();/* 第一个站点卖票 */Thread thread1 = new Thread(t);thread1.start();/* 第二个站点卖票 */Thread thread2 = new Thread(t);thread2.start();}}
程序结果:
第二种方式(正确):
/** * 通过继承的方式创建线程 * @author Liao * */class SyncTread extends Thread {/* 100张票 */private static int tickets = 100;/* 控制同步的标示 */private static String str = new String("s");@Overridepublic void run() {while (true) {synchronized (str) {if (tickets > 0) {System.out.printf("%s线程正在卖出第%d张票\n", Thread.currentThread().getName(), tickets);tickets --;} else {break;}}}}}public class ThreadSyncTest2 {public static void main(String[] args) {/*第一个线程卖票*/SyncTread t1 = new SyncTread();t1.start();/*第一个线程卖票*/SyncTread t2 = new SyncTread();t2.start();}}
这种方式也是正确的。
0 0
- 多线程之卖票程序
- Java多线程实例之卖票
- 利用多线程写一个卖票程序
- 多线程卖票
- 多线程实例之简单的卖票程序 ------记录与毕向东老师视频
- 多线程卖票之-NSThread、NSOperation、GCD
- 多线程模拟卖票程序,并统计各窗口售出数量
- 黑马程序员——多线程之卖票问题
- Java多线程之并发安全经典案例-卖票
- Java 多线程卖票演示
- 多线程,卖票系统
- Java多线程-卖票
- 卖票模拟多线程
- 实现Runnable 多线程卖票
- 线程示例:多线程卖票
- 多线程runnable实现卖票
- Java 多线程卖票
- java多线程卖票问题。
- 【Unity3D自学记录】Unity3D Web Player 的server端联网配置
- UML 总结
- lua入门之三:lua调用c/c++库(动态链接方式)
- js清除cookies
- 使用weak strong dance 解决 block 循环引用
- 多线程之卖票程序
- 禁止横竖屏
- spring Log4j关于No appenders could be found for logger的警告
- A. Black Square
- javascript的几种设计模式
- Jquery UI 中datepicker使用
- 编译hadoop-2.4.0的eclipse插件
- zencart分类批量打折插件
- 为动态生成的控件添加响应事件