多线程习题

题目1排队买票

模拟3个人排除买票,每人买1张票。售货员只有1张五元的钱,电影票5元一张,王大拿拿一张二十元的人民币排在谢大脚前面买票,谢大脚拿1张十元的人民币排在在赵四的前面买票,赵四拿1张五元的人民币排在最后。即最终的卖票次序是:谢大脚、赵四、王大拿

题解及思路

在这里插入代码片package thread;

/**
 * @author :HP
 * @create :2020-07-21 10:49:00
 * @description :五个问题:
 * 1、生命周期有新建、就绪、运行、阻塞、死亡五个阶段,new 一个线程对象时处于新建状态。start时处于就绪状态。获取cpu执行权时从就绪转到运行
 * 状态。调用sleep、join、wait、等待同步锁会使线程从运行状态进入阻塞状态。当sleep到时间、释放锁、notify/notifyall时会从阻塞态到就绪态。当线程的
 * run方法执行完毕、有异常没有解决、调用stop时线程进入死亡态
 * 2、同步监视器俗称锁。在一个同步代码块中需要指定锁。锁可以是任意的对象。多个线程必须使用同一把锁。
 * 共享数据:多个线程操作同一个数据就叫共享数据。
 * 3、sleep和wait的区别。
 * (1 sleep在Thread类,而wait在object类
 * (2 sleep随便写在哪里都可以,wait必须卸载同步代码块里。
 * (3 sleep不会自动释放锁,wait可以自动释放锁。
 * (4 sleep使时间到了就会使线程从阻塞态转到就绪态,wait需要notify才行
 * 4、写一个线程安全的懒汉单例模式
 * 5、创建多线程的方式:
 * (1 继承Thread类
 * (2 实现runnable接口
 * (3 实现callable接口
 * (4 使用线程池
 */
public class Practice {
    public static void main(String[] args) {
        TicketSeller seller = new TicketSeller();

        TicketThread t1= new TicketThread(seller, 5);
        TicketThread t2= new TicketThread(seller, 10);
        TicketThread t3= new TicketThread(seller, 20);

        t1.setName("赵四");
        t2.setName("谢大脚");
        t3.setName("王大拿");

        t3.start();
        t2.start();
        t1.start();

    }
}

/**
 * 买票线程,创建3个,模拟三人买票
 */
class TicketThread extends Thread{
    private TicketSeller seller;
    private int money;

    public TicketThread(TicketSeller seller, int money) {
        this.seller = seller;
        this.money = money;
    }

    @Override
    public void run() {
        seller.buyTicket(money);
    }
}

/**
 * 售票员,模拟售票可能遇到的3种情况
 */
class TicketSeller {
    private int fiveAcount = 1, tenAcount = 0, twentyAcount = 0;

    public synchronized void buyTicket(int receiveMoney) {
        //收到5元
        if (receiveMoney == 5) {
            System.out.println(Thread.currentThread().getName()+"付钱5元,不用找钱");
            fiveAcount++;
        }
        //收到10元
        else if(receiveMoney== 10){
            //没有5元现金,需要让10元客户等待,
            while (fiveAcount<1){
                System.out.println(Thread.currentThread().getName()+"付钱10元,现在没有零钱,请等待");
                try {
                    wait();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
            //有5元零钱,进行操作
            System.out.println(Thread.currentThread().getName()+"付了10元"+"找给"+Thread.currentThread().getName()+"5元");
            fiveAcount--;
            tenAcount++;
        }
        //收到20元
        else {
            //没有同时拥有5元和10元
            while (fiveAcount<1 || tenAcount<1){
                System.out.println(Thread.currentThread().getName()+"付钱20元,现在没有零钱,请等待");
                try {
                    wait();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
            //同时拥有5元和10元,可以给20元找零
            System.out.println(Thread.currentThread().getName()+"付了20元"+"找给"+Thread.currentThread().getName()+"15元");
            twentyAcount++;
            fiveAcount--;
            tenAcount--;
        }
        //卖票成功,通知其他人刷新状态,判断是否仍需等待。
        notifyAll();
    }
}

题目2

三个线程通讯(例如三窗口不连续卖票)

public class Demo01 {
	public static void main(String[] args) {
		//三个线程间的通讯
		MyTask task = new MyTask();
		new Thread(){
			public void run() {
				while(true){
					try {
						task.task1();
					} catch (InterruptedException e1) {
						e1.printStackTrace();
					}
					try {
						Thread.sleep(10);
					} catch (InterruptedException e) {
						e.printStackTrace();
					}
				}
			};
		}.start();
		new Thread(){
			public void run() {
				while(true){
					try {
						task.task2();
					} catch (InterruptedException e1) {
						e1.printStackTrace();
					}
					try {
						Thread.sleep(10);
					} catch (InterruptedException e) {
						e.printStackTrace();
					}
				}
			};
		}.start();
		new Thread(){
			public void run() {
				while(true){
					try {
						task.task3();
					} catch (InterruptedException e1) {
						e1.printStackTrace();
					}
					try {
						Thread.sleep(10);
					} catch (InterruptedException e) {
						e.printStackTrace();
					}
				}
			};
		}.start();
	}
}

class MyTask{
	
	//标识 1:可以执行任务1,2:可以执行任务2, 3:可以执行任务3 
	int flag = 1;
	
	public synchronized void task1() throws InterruptedException{
		if(flag != 1){
			this.wait();//当前线程等待
			//this.wait(timeout);
		}
		
		System.out.println("1.银行信用卡自动还款任务...");
		flag = 2;
		//this.notify();//唤醒随机线程
		this.notifyAll();//唤醒所有等待线程
		
	}
	
	public synchronized void task2() throws InterruptedException{
		
		if(flag != 2){
			this.wait();//线程等待
		}
		
		System.out.println("2.银行储蓄卡自动结算利息任务...");
		flag = 3;
		//this.notify();//唤醒其它线程
		this.notifyAll();
	}
	
	public synchronized void task3() throws InterruptedException{
			if(flag != 3){
				this.wait();//线程等待
			}
			
			System.out.println("3.银行短信提醒任务...");
			flag = 1;
			//this.notify();//唤醒其它线程
			this.notifyAll();
	}
}

题目3

生产者与消费者问题

我总结了一下我容易出现的问题:1、同步的代码块容易出错,很容易搞错应该同步那些地方,比如while(true){…}这个while就不应该被包含在同步块之内.以后分析多线程问题一定要注意只对共享数据操作的时候加锁,其他地方别加锁,别想着在方法上加个synchronized就完事了,还是得分析
2、对线程通信的知识理解不够透彻。比如wait、notify、notifyAll。这些方法还需要加强实践练习。

package thread;

/**
 * @author :HP
 * @create :2020-07-21 10:49:00
 * @description :五个问题:
 * 1、生命周期有新建、就绪、运行、阻塞、死亡五个阶段,new 一个线程对象时处于新建状态。start时处于就绪状态。获取cpu执行权时从就绪转到运行
 * 状态。调用sleep、join、wait、等待同步锁会使线程从运行状态进入阻塞状态。当sleep到时间、释放锁、notify/notifyall时会从阻塞态到就绪态。当线程的
 * run方法执行完毕、有异常没有解决、调用stop时线程进入死亡态
 * 2、同步监视器俗称锁。在一个同步代码块中需要指定锁。锁可以是任意的对象。多个线程必须使用同一把锁。
 * 共享数据:多个线程操作同一个数据就叫共享数据。
 * 3、sleep和wait的区别。
 * (1 sleep在Thread类,而wait在object类
 * (2 sleep随便写在哪里都可以,wait必须卸载同步代码块里。
 * (3 sleep不会自动释放锁,wait可以自动释放锁。
 * (4 sleep使时间到了就会使线程从阻塞态转到就绪态,wait需要notify才行
 * 4、写一个线程安全的懒汉单例模式
 * 5、创建多线程的方式:
 * (1 继承Thread类
 * (2 实现runnable接口
 * (3 实现callable接口
 * (4 使用线程池
 */
public class Practice {
    public static void main(String[] args) {
        Repository repository =new Repository();

        Producer1 producer1 = new Producer1(repository);
        Consumer1 consumer1 = new Consumer1(repository);

        producer1.setName("生产者");
        consumer1.setName("消费者");

        producer1.start();
        consumer1.start();
    }
}

class Repository{
    //仓库容量,初始为0,最大为4
    public static final int MAX_OPACITY=4;
    private int opacity=0;

    /**
     * 消费,当容量等于4时暂停生产
     */
    public void producer(){
        //容量未满时,生产,且通知消费者
        while (true) {
            synchronized (this) {
                if (opacity < MAX_OPACITY) {
                    try {
                        Thread.sleep(40);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }

                    opacity++;
                    System.out.println(Thread.currentThread().getName()+":生产产品第" + opacity + "个产品");
                    this.notifyAll();
                } else {
                    //容量满了,等待
                    try {
                        this.wait();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }
        }
    }

    /**
     * 消费,只能在容量>0时消费,容量等于0时等待
     */
    public void consumer(){
        while (true){
            synchronized (this) {
                if(opacity>0){
                    try {
                        Thread.sleep(20);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }

                    System.out.println(Thread.currentThread().getName()+":消费了第"+opacity+"个产品");
                    opacity--;
                    this.notifyAll();
                }
                else {
                    try {
                        this.wait();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }
        }

    }
}

class Producer1 extends Thread{
    private Repository repository;

    public Producer1(Repository repository) {
        this.repository = repository;
    }

    @Override
    public void run() {
        repository.producer();
    }
}

class Consumer1 extends Thread{
    private Repository repository;

    public Consumer1(Repository repository) {
        this.repository = repository;
    }

    @Override
    public void run() {
        repository.consumer();
    }
}
  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值