Java——第七章(进程和多线程)—项目案例

时间:2021-10-07 15:59:48

1、之前有做过打印图形的程序,现在要通过两个线程对象打印出三角形和矩形,要求两

个图形不能错乱。

三角形Thread:

public class SanjiaoThread implements Runnable{
    private int hang=5;
    private Object o ;
    @Override
    public void run() {
        // TODO Auto-generated method stub
        synchronized (o) {



        for (int i = 0; i < hang; i++) {
            for (int j = 0; j < hang-i-1; j++) {
                System.out.print(" ");
            }
            for (int j = 0; j < 2*i+1; j++) {
                System.out.print("*");
            }
            System.out.println();
        }
        }
    }
    public int getHang() {
        return hang;
    }
    public void setHang(int hang) {
        this.hang = hang;
    }
    public Object getO() {
        return o;
    }
    public void setO(Object o) {
        this.o = o;
    }


}

矩形Thread:

public class JuXingThread implements Runnable{
    private Object o ;
    @Override
    public void run() {
        // TODO Auto-generated method stub
        synchronized (o) {


        SanjiaoThread st = new SanjiaoThread();

        for (int i = 0; i < st.getHang(); i++) {
            for (int j = 0; j < st.getHang()*2; j++) {
                System.out.print("*");
            }
            System.out.println();
        }
        }
    }
    public Object getO() {
        return o;
    }
    public void setO(Object o) {
        this.o = o;
    }


}

测试类:

public class Test02 {

    public static void main(String[] args) throws Exception {
        // TODO Auto-generated method stub
        Object o = new Object();


        SanjiaoThread st = new SanjiaoThread();
        st.setO(o);
        Thread t = new Thread(st,"三角形: ");
        JuXingThread jt = new JuXingThread();
        jt.setO(o);
        Thread t1 =new Thread(jt,"矩形: ");

        t.start();
        t1.start();
    }

}

通常可以在线程类里面定义要锁定的资源对象,通过主线程中创建该资源对象,通过赋

值给哪个线程,哪个线程获得资源的拥有权进行操作。

2、有一个男生叫晓军,在双十一这天要取银行卡里5000中的3000,然而他媳妇正好购物

车中放了3000块钱的包包和衣服,俩人同时取钱,要求一人取出后另一个人账号小于

3000取不出来,解决线程同步问题。

线程类:

public class QuqianRun1 extends Thread{
    private static Integer money=5000;
    boolean flag = false;
    @Override
    public void run() {

        synchronized (money) {
            if(flag)
            {
                if(money>3000)
                {
                    try {
                        Thread.sleep(1000);
                    } catch (InterruptedException e) {
                        // TODO Auto-generated catch block
                        e.printStackTrace();
                    }

                    System.out.println(Thread.currentThread().getName()+": 能取钱了!");
                    money-=3000;
                    System.out.println(Thread.currentThread().getName()+"剩余:"+money);
                }



            }else{

                if(money>3000)
                {
                    System.out.println(Thread.currentThread().getName()+": 能花钱了!");
                    money-=3000;
                    System.out.println(Thread.currentThread().getName()+"剩余:"+money);
                }

            }
            }


    }
    public boolean isFlag() {
        return flag;
    }
    public void setFlag(boolean flag) {
        this.flag = flag;
    }

}

测试类:

public class Test04 {

    public static void main(String[] args) {
        // TODO Auto-generated method stub

        QuqianRun1 qr = new QuqianRun1();
        qr.setName("晓军");
        qr.setFlag(true);
        QuqianRun1 qr1 = new QuqianRun1();
        qr1.setName("他媳妇");
        qr1.setFlag(false);
        qr.start();
        qr1.start();


    }

}

这个是随机运行,两个线程不一定轮到谁,多试几次。。结果就会不一样。

3、电影票购买,分为到店买和网上购买,最近上映的《奇异博士》,晚场票量一共500

张,两种购买方式不冲突,低于0张不可购买。

线程类:

import java.util.Scanner;

public class DianYingPiao extends Thread{
// private Object o;
    private static Integer count=500;
    private boolean b =true;
    private int zhang =0;
    @Override
    public void run() {
        // TODO Auto-generated method stub
        if(b)
        {
            synchronized (count) {

                System.out.println("输入到店要买的张数:");
                Scanner sc = new Scanner(System.in);
                zhang =sc.nextInt();
                if(count>=zhang)
                {
                    count-=zhang;
                    System.out.println("成功购买"+zhang+"张电影票!剩余"+count+"张。");
                }
                else{
                    System.out.println("余量不足!");
                }
            }
        }else
        {

            synchronized (count) {
                System.out.println("输入网上要买的张数:");
                Scanner sc = new Scanner(System.in);
                zhang =sc.nextInt();
                if(count>=zhang)
                {
                    count-=zhang;
                    System.out.println("成功购买"+zhang+"张电影票!剩余"+count+"张。");
                }
                else{
                    System.out.println("余量不足!");
                }
            }

        }



    }
    public boolean isB() {
        return b;
    }
    public void setB(boolean b) {
        this.b = b;
    }
// public Object getO() {
// return o;
// }
// public void setO(Object o) {
// this.o = o;
// }

}

测试类:

public class Test07 {

    public static void main(String[] args) {
        // TODO Auto-generated method stub
// Object o = new Object();
        DianYingPiao dyp1 = new DianYingPiao();
        DianYingPiao dyp2 = new DianYingPiao();
        dyp2.setB(false);
// dyp1.setO(o);
// dyp2.setO(o);
        dyp1.start();
        dyp2.start();

    }

}

线程类和测试类中注释的地方第二种解决线程同步问题方法,通过主类设置给哪个线程

上锁资源进行操作。使用这种方式需要在synchronized中改成object对象o,而不是

count。

4.科学家吃饭问题,5个科学家吃饭,每个人只有一只筷子,要想吃到饭,必须用两只筷

子,但是如果每个人都要等其中 一个人贡献出来自己的筷子,都吃不上饭,只要有一个

人贡献出来,大家都可以吃到饭。这就是科学家吃饭问题,这里为了更好演示,举例2个

人吃饭。

第二个人的线程:

public class Thread2 extends Thread{
    private Object o1;
    private Object o2;


    @Override
    public void run() {
        // TODO Auto-generated method stub
        synchronized (o2) {
            System.out.println("我已经有我一只筷子了,再给我一只呗!");

            synchronized (o1) {
                System.out.println("我终于要开吃啦!");
                o1.notify();//唤醒之前的线程wait方法。使其获得时间片。
            }
        }



    }

第一个人的线程:

public class Thread1 extends Thread{
    private Object o1;
    private Object o2;

    @Override
    public void run() {
        // TODO Auto-generated method stub
        synchronized (o1) {
            try {
                o1.wait();//放在synchronized结构内使用。将o1所有权给释放给下个线程
            } catch (InterruptedException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
            System.out.println("给我筷子,你哥我要吃饭!");

            synchronized (o2) {
                System.out.println("终于吃到饭了!");
            }
        }

    }

    public Thread1(Object o1, Object o2) {
        super();
        this.o1 = o1;
        this.o2 = o2;
    }


}

测试类:

public class Test06 {

    public static void main(String[] args) throws Exception {
        // TODO Auto-generated method stub
        Object o1 = new Object();
        Object o2 = new Object();
        Thread1 t1 = new Thread1(o1, o2);
        Thread2 t2 = new Thread2(o1, o2);
        t1.start();
        t2.start();

    }

}

这样是第一个人先贡献自己的筷子,永远第二个人先吃饭,然后第一个人再吃。

5、介绍一下好玩的类TimerTast(计时器任务)—Timer(计时器),通过创建Timer

类对象调用schedule方法,来定时做一些事情,例如闹钟嘛、、

代码:

import java.awt.Toolkit;
import java.util.Date;
import java.util.Timer;
import java.util.TimerTask;

public class Timermain {

    public static void main(String[] args) throws Exception {
        // TODO Auto-generated method stub
        Timer timer = new Timer();
        Date time = new Date(System.currentTimeMillis()+5000);
        timer.schedule(new TimerTask() {

            @Override
            public void run() {
                // TODO Auto-generated method stub
                Toolkit.getDefaultToolkit().beep();
            }
        }, time, 500);
        timer.scheduleAtFixedRate(new TimerTask() {

            @Override
            public void run() {
                // TODO Auto-generated method stub

            }
        }, 5000, 600);
        Thread.sleep(10000);
        timer.cancel();
    }

}

schedule(TimerTask task, Date firstTime, long period) ;

这个方法中第一个是TimerTask的一个对象,第二个参数是开始的时间,第三个参数是

间隔时间。

可以是向上面的匿名内部类之间在main中创建task,也可以在外面建一个TimerTast

类,传入其对象都可以。匿名内部类在Android中经常用到,方便。

run方法就是到点时要执行的操作,Toolkit.getDefaultToolkit().beep();是调用电脑系

统默认声音。。