多线程使用同步代码块的方式实现两个窗口卖票(不重复)

使用两个线程实现两个窗口卖票,不能卖出重复的票,两个线程使用同一个数据
结果图

1.先建立一个共享的数据存储,这里用ArrayList来实现

package com.leiyustudy.thread.safe;
import java.util.ArrayList;
/** * * */
public class TicketService {
	
	private ArrayList<String>  all;
	
	public TicketService() {
		all =new ArrayList<>();
		all.add("01车01A");
		all.add("01车01B");
		all.add("01车01C");
		all.add("01车01D");
		all.add("01车01F");
		
		all.add("02车02A");
		all.add("02车02B");
		all.add("02车02C");
		all.add("02车02D");
		all.add("02车02F");
	}

	//查询是否还有票
	
	public boolean hasTicket() {
		return all.size()>0;
	}
	
	//卖票
	public String sale() {
		return all.remove(0);
	}
	/** * @param args */
}

2.创建一个类来继承Thread类实现多线程卖票

/** * */
package com.leiyustudy.thread.safe;

/** * @author 雷雨 *同时两个人卖票 *两个线程使用了共享的同一数据,就可能有线程安全问题. *如何判断 *是否有多个线程共享一个数据 *(2)是否有多个线程共同操作和访问同一个数据 * *如何解决? 加锁 *同步: *(1)同步的锁对象可以是任意类型的对象(意思就是不限制它的类型,只有共享的人都默认承认这个锁的存在就可以 *(2)使用共享数据的多个线程承认这个锁 * *两种形式; *(1)同步代码块 *语法格式: *synchronized(需要同步的锁对象){ * 需要锁着的代码:一个线程在运行代码期间不想别的线程加入进来, *} * *(2)同步方法 */
public class TestTicket {

	/** * @param args */
	public static void main(String[] args) {
		// TODO 自动生成的方法存根

		Ticketsaler t1 = new Ticketsaler("窗口一");
		Ticketsaler t2 = new Ticketsaler("窗口二");
		
		t1.start();
		t2.start();
		

	}

}
class Ticketsaler extends Thread{
	private static TicketService ts = new TicketService();
	
	public  Ticketsaler (String name) {
		super(name);
	}
	public void run() {
		//这里锁的的ts对象时两个线程公用的对象,因为他是static的对象,但是同时也导致了锁着的ts对象(票库中的票全是窗口一线程卖出的)
		while(true) {
			
			synchronized (ts) {
				if(ts.hasTicket()) {
					try {
						Thread.sleep(1000);
						//这里用synchronized来锁,在sleep的过程中不释放锁对象
					} catch (InterruptedException e) {
						// TODO 自动生成的 catch 块
						e.printStackTrace();
					}
					System.out.println(getName()+"卖出了"+ts.sale());
				}
				else {
					break;
				}
			
			}
		}
	
	}
}

3.创建一个类来实现Runnable接口来实现多线程卖票

/** * */
package com.leiyustudy.thread.safe;

import org.junit.runner.notification.RunListener.ThreadSafe;

/** * @author 雷雨 * * *继承Thread和实现Runnable的区别: *共享对象 *Thread继承来做的话必须用静态的对象 *而Runnable来做只需要得到共同的Runnable的对象,而不一定要静态对象,静态对象的生命周期很长,不建议大量使用 *(2)选择锁对象时比较方便 *因为在Runnable的run方法中的对象就是Runnable的同一个对象,所以可以用this来锁对象 *而继承Thread的方法就不能用this来锁 *(3)继承有单继承限制,实现没有限制 *在java程序开发中尽量面向接口编程 * */
public class TestTicketRunnable {
	
	public static void main(String[] args) {
		MyRunnable r1 = new MyRunnable();

		Thread t1 = new Thread(r1,"窗口一");
		Thread t2 = new Thread(r1,"窗口二");
		
		t1.start();
		t2.start();
		
		
	}

}
class MyRunnable implements Runnable{

	private TicketService ts = new TicketService();

	@Override
	public void run() {

		while(true) {
			
			synchronized (ts) {
				if(ts.hasTicket()) {
					try {
						Thread.sleep(1000);
						
					} catch (InterruptedException e) {
						// TODO 自动生成的 catch 块
						e.printStackTrace();
					}
					System.out.println(Thread.currentThread().getName()+"卖出了"+ts.sale());
				}
				else {
					break;
				}
			
			}
		}
		
	}
	
}

继承Thread类和实现Runnable接口来实现多线程的方式不同,对于实现Runnable接口的方式来说,对于选择锁的对象比较简单,但是线程的启动得依靠Thread对象来启动.总的来说,java尽量面向接口编程.

全部评论

相关推荐

点赞 评论 收藏
分享
我即大橘:耐泡王
点赞 评论 收藏
分享
评论
点赞
收藏
分享
牛客网
牛客企业服务