多线程练习题目

来源:互联网 发布:蓝凌软件下载 编辑:程序博客网 时间:2024/06/07 07:42

最近在重新学习多线程的相关知识,发现多线程是真的有意思,完全打破以前的那种只有1条执行流的执行方式, 而是多线程一起跑起来,并发的进行,所以你会看到他的输出会完全打破你之前的按序输出, 他 根据底层OS的处理器进行随机调度某一个线程进行执行;因为时间很短,所以你会感觉像并发进行;
关于这方面的知识,就牵扯到:多个线程之间的通信方式,怎么控制多个线程来执行达到你想要的结果;以及他们之间的同步问题;这2方面是关键;
学习多线程思维模式也打破了,从空间维度类比有种从1维过渡到2维、3维的感觉;
下面通过几道题目实践感受下,多线程的并发、以及他们之间的通信,同步。

1.此题目可以用同步代码块,也可以用同步方法。
/** *1. 写2个线程,其中一个线程打印1\~52,另一个线程打印A\~Z, *打印顺序应该是12A34B56C…5152Z。 *该题需要用到多线程通信的知识。 * 不理解的话可以Debug下一步一步的走走看  * @author lwx * */public class PrintThread {    public static void main(String[] args) {        Object obj = new Object();        new NumberThread(obj).start();        new ZimuThread(obj).start();    }}class NumberThread extends Thread {    private Object obj;    public NumberThread(Object obj) {        this.obj = obj;    }    public void run() {        //加锁        synchronized (obj) {            for (int i = 1; i <= 52; i++) {                System.out.print(i);                if (i % 2 == 0) {                    obj.notifyAll();                    try {                        obj.wait();                    } catch (InterruptedException e) {                        e.printStackTrace();                    }                }            }        }    }}class ZimuThread extends Thread {    private Object obj;    public ZimuThread(Object obj) {        this.obj = obj;    }    public void run() {        synchronized (obj) {            for (int i = 0; i < 26; i++) {                System.out.print((char) (i + 'A'));                // 唤醒其他线程并且让线程等待!                obj.notifyAll();                try {                    obj.wait();                } catch (InterruptedException e) {                    e.printStackTrace();                }            }        }    }}总结:由于线程A和线程B持有同一个MyObject类的对象object,尽管这两个线程需要调用不同的方法,但是它们是同步执行的,比如:线程B需要等待线程A执行完了methodA()方法之后,它才能执行methodB()方法。这样,线程A和线程B就实现了 通信。这种方式,本质上就是“共享内存”式的通信。多个线程需要访问同一个共享变量,谁拿到了锁(获得了访问权限),谁就可以执行。运行结果:12A34B56C78D910E1112F1314G1516H1718I1920J2122K2324L2526M2728N2930O3132P3334Q3536R3738S3940T4142U4344V4546W4748X4950Y5152Z
1.创建一个包含这两种方法的类public class PrintStore {   //通过一个标识flag来确保打印字母的线程一定要等到打印数字线程执行后才得到执行机会。    private boolean flag = false;    public synchronized void printNumber() {        // System.out.printf("打印数字线程启动,此时flag为 %s \n", flag);        for (int i = 1; i < 53; i++) {            System.out.print(i);            if (i % 2 == 0) {                flag = true;                notifyAll();                try {                    wait();                } catch (InterruptedException e) {                    e.printStackTrace();                }            }        }    }    public synchronized void printLetter() {        // System.out.printf("打印字母线程启动,此时flag为 %s \n", flag);        char[] zimu = new char[26];        for (int i = 0; i < 26; i++) {            zimu[i] = (char) (i + 65);        }        for (char c : zimu) {            if (flag) {                System.out.print(c);                flag = false;                notify();                try {                    wait();                } catch (InterruptedException e) {                    e.printStackTrace();                }            }        }    }}2.写两个线程类class PrintNumber implements Runnable {    private PrintStore ps;     public PrintNumber(PrintStore ps) {           this.ps=ps;          }    @Override    public void run() {    ps.printNumber();   }}  class PrintLetter implements Runnable {    private PrintStore ps;     public PrintLetter(PrintStore ps) {        this.ps=ps;    }    @Override    public void run() {      ps.printLetter();         }}3.主方法测试public class HomeWork1 {    public static void main(String[] args) {    PrintStore ps=new PrintStore();    PrintNumber pn=new PrintNumber(ps);    PrintLetter pl=new PrintLetter(ps);    new Thread(pn).start();    new Thread(pl).start();    }}总结:写这个程序过程中遇到了不少问题,一开始我创建线程时,没有用到共享资源,导致两个线程都是独立的,然后发现线程A的wait()方法和notify()方法,只能暂停和启动A线程本身,并不会通知B线程启动。后来仔细研究了一下这里的问题:Object类的wait(),notify(),notifyAll()方法必须由同步监视器对象来调用。 * 对于使用synchronized修饰的同步方法,因为该类的默认实例(this)就是同步监视器,所以可以在同步方法中直接调用这三个方法; * 对于使用synchronized修饰的同步代码块,同步监视器是synchronized后括号里的对象,所以必须使用该对象调用。这三个方法,都只能对同一个同步监视器上的线程有效,所以我最开始的那种方式,其实存在着两个同步监视器,线程A和线程B各自有各自的同步监视器,所以A不能成功通知到B。后来参考这个: 深入理解Java多线程之线程间的通信方式 发现两个线程之间如果想要成功的进行通信,必须要创建一个线程之间的共享资源,然后把这个共享资源当做同步监视器。
1.停车场:含有属性:车位状态   同步的方法:停车、开车/** *   2.假设车库有3个车位(可以通过boolean[]数组来表示车库)可以停车, *   写一个程序模拟多个用户开车离开,停车入库的效果。注意:车位有车时不能停车。 * @author lwx * */public class Park {    private int state = 3;//车场中剩余的车位数    public synchronized void CarIn(int i){        try{        if(state == 0){            System.out.println("目前空余车位为:"+ state+"请等待");             wait();        }           System.out.println(i+"号车停车成功");           state--;           System.out.println("目前剩余车位: " + state);           notifyAll();    }catch (InterruptedException e){        e.printStackTrace();    }  }    public synchronized void CarOut(int i){        try{            if(state ==3){                wait();            }              System.out.println(i +"号车已驶出");              state++;              System.out.println("目前剩余车位: " + state);              notify();        }catch(InterruptedException e){            e.printStackTrace();        }    }}2.停车线程:模拟用户停车20次class CarInThread extends Thread{    Park park;    public CarInThread(Park park){        this.park = park;    }    public void run(){        for(int i=1;i<20;i++){            park.CarIn(i);        }    }}3.开车线程:模拟用户开车20次class CarOutThread extends Thread{Park park;public CarOutThread(Park park) {this.park=park;}@Override    public void run() {        super.run();        for(int i=1;i<20;i++){            park.CarOut(i);        }    }}4.测试:public class Test {    public static void main(String[] args){          Park park =new Park();          CarInThread cInThread=new CarInThread(park);          CarOutThread cOutThread=new CarOutThread(park);          new Thread(cOutThread).start();          new Thread(cInThread).start();    }}运行结果:0号车停车成功目前剩余车位: 21号车停车成功目前剩余车位: 12号车停车成功目前剩余车位: 0目前空余车位为:0请等待0号车已驶出目前剩余车位: 11号车已驶出目前剩余车位: 22号车已驶出目前剩余车位: 33号车停车成功目前剩余车位: 24号车停车成功目前剩余车位: 15号车停车成功目前剩余车位: 0目前空余车位为:0请等待3号车已驶出目前剩余车位: 14号车已驶出目前剩余车位: 25号车已驶出目前剩余车位: 36号车停车成功目前剩余车位: 27号车停车成功目前剩余车位: 18号车停车成功目前剩余车位: 0目前空余车位为:0请等待6号车已驶出目前剩余车位: 17号车已驶出目前剩余车位: 28号车已驶出目前剩余车位: 39号车停车成功目前剩余车位: 29号车已驶出目前剩余车位: 3总结:此题目也可以用对象锁+condition实现通信;也可以用队列来做,基本都是这样子,注意要实现同步+通信