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

使用两个线程实现两个窗口卖票,不能卖出重复的票,两个线程使用同一个数据
结果图
在这里插入图片描述
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 雷雨
 *同时两个人卖票
 *两个线程使用了共享的同一数据,就可能有线程安全问题.
 *如何判断
 *(1)是否有多个线程共享一个数据
 *(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的区别:
 *(1)共享对象
 *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尽量面向接口编程.

发布了82 篇原创文章 · 获赞 26 · 访问量 3991

猜你喜欢

转载自blog.csdn.net/qq_40742223/article/details/104668651