题目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();
}
}