学习Java第三十天--多线程的经典问题案例

死锁问题(synchronized和Lock)、生产者消费者问题(Queue)

  • 死锁问题、售票案例、synchronized和Lock两种方法的时间比较
  • 生产者消费者问题、Queue接口案例

死锁问题、售票案例、synchronized和Lock两种方法的时间比较

import java.util.concurrent.locks.ReentrantLock;

public class SellTicket {

	public static void main(String[] args) throws InterruptedException {
		Thread thread;//创建线程
		Tickets tickets= new Tickets();//创建票的容器
		
		Conductor c1 = new Conductor("Tom" , tickets , true);
		long start = System.currentTimeMillis();
		for(int i = 0 ; i < 500 ; i++) {
			thread = new Thread(c1);
			thread.start();
			thread.join();
		}
		long end = System.currentTimeMillis();
		System.out.println("synchronized方式售票时间为:"+(end - start));
		
		
		Conductor c2 = new Conductor("Rose" , tickets , false);
		start = System.currentTimeMillis();
		for(int i = 0 ; i < 500 ; i++) {
			thread = new Thread(c2);
			thread.start();
			thread.join();
		}
		end = System.currentTimeMillis();
		System.out.println("Lock方式售票时间为:"+(end - start));
	}

}

//存放票的容器
class Tickets{
	private int tickets = 1000;//总共1000张票
	ReentrantLock lock = new ReentrantLock();
	
	
	public int sellTicketSyn() {//使用synchronized的售票方式
		if(tickets == 0) {//如果票卖完了则返回0
			return 0;
		}
		synchronized(this) {//为原子操作加锁
			this.tickets--;//票数-1
			return tickets;//返回剩余票数
		}
	}
	
	public int sellTicketLock() {//使用Lock的售票方式
		if(tickets == 0) {//如果票卖完了则返回0
			return 0;
		}
		lock.lock();//上锁
		this.tickets--;//票数-1
		lock.unlock();//释放锁
		return tickets;//返回剩余票数
	}
}

//售票员类
class Conductor implements Runnable{
	private String name;//售票员姓名
	private Tickets tickets;//票的容器
	private boolean flag;//售票方式
	
	public Conductor(String name , Tickets tickets , boolean flag){
		this.name = name;
		this.tickets = tickets;
		this.flag = flag;
	}

	@Override
	public void run() {
		int num;
		if(this.flag == true) {
			num = tickets.sellTicketSyn();
		}else {
			num = tickets.sellTicketLock();
		}
		if(num == 0) {
			return;
		}
//		System.out.println(this.name+"出售了一张票");
	}

}

输出结果:

synchronized方式售票时间为:100
Lock方式售票时间为:81

一般来说Lock的效率更高些。

生产者消费者问题、Queue接口案例

import java.util.Random;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class ProducerConsumer {
	
	public static void main(String[] args) {
		ExecutorService exService = Executors.newFixedThreadPool(3);//创建线程池
		BlockingQueue<Integer> queue = new ArrayBlockingQueue<>(100);//创建队列
		
		Producer p = new Producer(queue);
		Consumer c1 = new Consumer(queue);
		
		exService.submit(p);//生产者线程
		exService.submit(c1);//消费者线程
	}

}

class Producer implements Runnable{

	private final BlockingQueue<Integer> queue;//货物队列
	
	public Producer(BlockingQueue<Integer> q) {
		this.queue = q;
	}
	
	@Override
	public void run() {
			try {
				while(true) {
					//模拟耗时1s
					Thread.sleep(1000);
					queue.put(produce());//生产方法
				}
				
			}catch(InterruptedException e) {
				e.printStackTrace();
			}
		}
	
	private int produce() {
		int n = new Random().nextInt(1000);//生产的货物数目
		Thread.currentThread().setName("生产者线程");
		System.out.println(Thread.currentThread().getName()+"生产:"+n+"件");
		return n;
	}
}

class Consumer implements Runnable{
	
	private final BlockingQueue<Integer> queue;

	public Consumer(BlockingQueue<Integer> q) {
		this.queue = q;
	}
	
	@Override
	public void run() {
		while(true) {
			try {
				//模拟耗时2s
				Thread.sleep(2000);
				consume(queue.take());//获取最早生产的一批货物
			}catch(InterruptedException e) {
				e.printStackTrace();
			}
		}
	}
	
	private void consume(Integer n) {//消费者购买货物
		Thread.currentThread().setName("消费者");
		System.out.println(Thread.currentThread().getName()+"购买:"+n+"件");
	}
	
}

输出结果:

生产者线程生产:267件
消费者购买:267件
生产者线程生产:427件
生产者线程生产:113件
消费者购买:427件
生产者线程生产:199件
生产者线程生产:671件
消费者购买:113件
生产者线程生产:765件
生产者线程生产:102件
消费者购买:199件
生产者线程生产:377件
生产者线程生产:483件
消费者购买:671

Queue队列对生产者消费者问题的解决更加便利。

你可能感兴趣的:(学习Java)