创建线程问题的实例

一、甲乙两人每次一千,分三次分别向同一个账号各自存入三千:

思路:①提取共同数据②编写用于创建多线程对象的继承类③创建测试类,通过线程对象.start()方法创建线程

其中将账号单独提取出来构建一个类,可以有效的减少账号与人之间的耦合性。账号需要编写余额属性,一个带参的构造方法(需要通过在测试类中创建账号类型的引用类型数据对象,将账号对象通过引用类型方式作为人构造器中的形参传入,从而将账号与人联系起来),以及一个存钱的方法。

//构建共享数据
class Account{
    private double balance;

    public Account(int balance) {
        this.balance = balance;
    }

    //对象中需要有存钱方法
    public synchronized void SaveMonney(double monney){
        if (monney > 0){
            balance += monney;
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println(Thread.currentThread().getName()+"存钱成功,余额为:"+balance);
        }
    }
}

//构建对象创造类Customer,便于构造甲乙两个对象
class Customer extends Thread{
    private Account acc;
    public Customer(Account acc){
        this.acc = acc;
    }

    @Override
    public void run() {
        for (int i = 0; i < 3; i++) {
            acc.SaveMonney(1000);
        }
    }

}

public class AccountTest {
    public static void main(String[] args) {
        Account account = new Account(0);
        Customer customer1 = new Customer(account);
        Customer customer2 = new Customer(account);
        customer1.setName("甲");
        customer2.setName("乙");
        customer1.start();  //调用run()方法
        customer2.start();
    }
}

注意:此处的同步监视器为this,因为synchronized同步方法在Account类里面,且测试类中只new了一个Account对象,所以此时Account对象为唯一的对象,即可用this。 

二、使用两个线程打印1-100,两个线程交替打印:

思路:①创建一个Number类实现Runnable接口②创建测试类,通过线程对象.start()方法创建线程。此问题中使用了notify()与wait()两个方法,分别在处理共享数据代码前与代码后使用,notify()表示重新加锁,wait()表示释放锁。于是得到的流程为,第一个线程进去完成共享数据操作,到达wait()方法后,释放同步监视器,完成它操作的同时,第二个线程由于锁开了于是进来了,首先遇到notify(),马上加锁限制此时只能一个线程进入,完成共享数据操作后,到达wait()方法,释放锁。如此循环,最后得到两个线程交替有序的运行操作。

class Number implements Runnable{
    private int number = 1;
    @Override
    public void run() {
        while (true) {
            synchronized (this) {
                notify();
                if (number <=100){
                    System.out.println(Thread.currentThread().getName() + "打印的数字为:" + number);
                    number++;
                    try {
                        wait();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }else
                    break;
            }
        }
    }
}

public class NumberTest {
    public static void main(String[] args) {
        Number number = new Number();
        Thread t1 = new Thread(number);
        Thread t2 = new Thread(number);

        t1.setName("线程一");
        t2.setName("线程二");

        t1.start();
        t2.start();
    }
}

 注意,wait()与notify()只能在同步代码块与同步方法中使用,不能在lock中使用。wait()与notify()都必须是由同一个同步监视器调用,否则会出现java.lang.IllegalMonitorStateException错误,且wait()与notify()都是定义在Object类中的方法,所以说,若不再synchronized括号内,则调用者会由this变为Object。

class Number implements Runnable{
    private int number = 1;
    @Override
    public void run() {
        while (true) {
        notify();    //此时调用notify()方法的不是this同步监视器,而是Object类,会报错。
            synchronized (this) {       
                if (number <=100){
                    System.out.println(Thread.currentThread().getName() + "打印的数字为:" + number);
                    number++;
                    try {
                        wait();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }else
                    break;
            }
        }
    }
}

三、生产者有固定的生产上限,比如二十个,达到二十个则会被叫停,若产品少于二十则会通知生产者继续生产;消费者可以取走产品,若店里没有产品了,则被通知等一下,如果有产品了则通知消费者取走产品。

思路:整体思路的创建与上述相同,可以培养一下从整体框架的构建到局部细节的编写。例如先把共享数据类,继承Thread类的两个类,以及测试类搭建好。通过测试类知道我要干什么,需要什么对象,创建对象是否需要带参构造器,创建好对象后,需要调用什么方法。此时需要的细节方法操作就都一目了然,通过art+enter可以在对应的类中创建构造器与方法。

//测试类
public class ProductTest {
    public static void main(String[] args) {
        Produce produce = new Produce(0);
        Productor p1 = new Productor(produce);
        Customer c1 = new Customer(produce);

        //修改线程名字
        p1.setName("生产者1");
        c1.setName("消费者1");

        //开始线程操作
        p1.start();
        c1.start();
    }
}

//共享数据
class Produce{
    private int num =0;
    public Produce(int num){
        this.num = num;
    }

    //生产产品
    public synchronized void producer(){ //此时同步监视器为this,即为Produce创建的对象produce。因为从始至终就创建了一个produce对象
        if (num < 20){
            num++;
            notify();
            System.out.println(Thread.currentThread().getName()+"正在生产第"+num+"件产品");
        }else {
            try {
                wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }

    //消费产品
    public synchronized void consume(){ //此时同步监视器为this,即为Produce创建的对象produce。因为从始至终就创建了一个produce对象
        if (num > 0){
            notify();
            System.out.println(Thread.currentThread().getName()+"正在消费第"+num+"件产品");
            num--;
        }else {
            try {
                wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }

}

//线程创建类Productor
class Productor extends Thread{
    private Produce produce;
    public Productor(Produce produce){
        this.produce = produce;
    }

    @Override
    public void run() {
        System.out.println(getName()+"开始生产>>>>>>>>>>>>>>>>>>>>>>>");
        while (true){
            try {
                sleep(100);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            produce.producer();
        }
    }
}

//线程创建类Customer
class Customer extends Thread{
    private Produce produce;
    public Customer(Produce produce){
        this.produce = produce;
    }

    @Override
    public void run() {
        System.out.println(getName()+"开始消费>>>>>>>>>>>>>>>>>>>>>>>");
        while (true){
            try {
                sleep(100);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            produce.consume();
        }
    }
}

 注意:notify()需要考虑放置的位置,因为producer()与consume()都是用的同一个同步监视器,同一时间只能进入一个synchronized方法中,所以若当进入到producer()方法创建产品时,随之consume()会陷入阻塞状态(两个方法随机进入,producer()也可能进入阻塞状态,这里举例consume()进入阻塞状态),当完成此方法后,调用wait()释放锁。此时要考虑notify()放置的位置,只要producer()方法中num++一次,消费者就可进行消费产品操作,所以考虑将notify()放到num++后。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值