java - 线程 - 多线程处理

https://www.cnblogs.com/clamp7724/p/11648308.html

在基础中使用了java自带的Vector线程安全处理多线程。

这次试试用锁来进行处理

 

线程锁:

synchronized

使用synchronized修饰方法,这样调用这个方法的时候,这个方法会被锁定,只有当前对象使用完后才能释放让其他对象使用。
不加这个可能会多个对象同时访问这个方法,导致出现线程问题(比如出货方法,A运行到这个方法的判断是否还有货物,判断还有货物,B这时刚好也运行方法拿走了货物,A开始拿货就会报错)

public synchronized void 方法名(){...}
或者
synchronized (需要锁定的对象){ ... } 执行完代码后解锁

线程控制:
wait:
Object.wait() 让执行这个Object的线程进入等待状态,直到cpu再次分配资源(只要线程不消亡或者报错,cpu有空的时候还会自动分配资源给它执行),注意这里操作的对象是线程,多个单线程操作同一个对象,其中一个线程进入等待不影响其它线程操作这个对象。
如果在某个方法中写this.wait(); 进入等待状态的是当前操作这个对象的线程,不是当前class的对象。比如A调用了B中方法,这个方法有个this.wait(),执行到那里这个线程会断掉(不再继续往下执行),等待唤醒再继续。不影响C去调用B的方法。
所有线程都进入wait() ---》 假死状态。
防止假死需要找时机对线程进行唤醒(notify,notifyAll)

sleep:
Thread.sleep(等待时间毫秒)。 让调用方法的对象进入等待状态,等待时间到了自动醒来。


Object.notify:
唤醒当前对象的其中一个线程(cpu决定优先级,或者提前用 object.setPriority(int 优先级) 设置优先级,优先级为1-10, 10最高)

Object.notifyAll:
唤醒对象的所有线程。

生产消费者模型:
有人往仓库放,有人从仓库拿,多人同时操作同一个仓库。

主函数

package multi_thread;

public class MultiThreadTest {
    public static void main(String[] args) {
        Customer c1 = new Customer("消费者1");
        Customer c2 = new Customer("消费者2");
        Customer c3 = new Customer("消费者3");
        Customer c4 = new Customer("消费者4");

        Productor p1 = new Productor("生产者1");
        Productor p2 = new Productor("生产者2");
        //生产者优先级高一些,先生产再消费
        p1.setPriority(10);
        p2.setPriority(10);


        //初始10个产品,有4个消费者每人买20次,2个生产者每人生产25个,也就是说至少会有20次买不到(消费速度 > 生产速度,还没来得及生产出来也可能买不到)

        c1.start();
        c2.start();
        c3.start();
        c4.start();
        p1.start();
        p2.start();


    }
}

 

 

消费者

package multi_thread;

public class Customer extends Thread{ //消费者,买取货物
    private String name;
    public Customer(String name){
        this.name = name;
    }

    public void run(){
        for(int i = 0; i < 20; i++) {  //假设每个消费者需要20个产品
            buyGood();
        }
    }

    private void buyGood(){
        Goods g = Goods.getInstance();
        String s = g.removeGood();

        //多线程锁的另一种写法,在一段代码外面添加synchronized(上锁的对象){}
        //这样可以达到和方法上锁一样的效果
//        synchronized(g) {
//            s = g.removeGood();
//        }

        if(s != null){
            System.out.println(name + "买走了" + s);
        }
        else{
            System.out.println(name + "发现没货啦!");
//            try {
//                this.sleep(500);  //当前Customer对象等0.1秒再买
//                System.out.println(name + "又开始买东西了!");
//            } catch (InterruptedException e) {
//                e.printStackTrace();
//            }
            //让某个Thread 对象(c1继承了Thread)等待111毫秒后自动醒来
        }
    }
}

 

生产者

package multi_thread;

public class Productor extends Thread{ //生产者,增加货物
    private String name;
    public Productor(String name){
        this.name = name;
    }

    public void run(){
        for(int i = 0; i < 30; i++) {  //假设每个生产者生产30个产品停止,刚好满足消费
            productGood();
        }
    }

    private void productGood(){
        Goods g = Goods.getInstance();
        String s = g.addGood();
        System.out.println(name + "生产了" + s);

    }
}

 

货物仓库

package multi_thread;

import java.util.ArrayList;

public class Goods { //货物仓库,这次用String表示货物

    private int num = 1; //用来区分货物
    private static Goods goods = new Goods();
    private ArrayList<String> goodList = new ArrayList<>();  //用String代表货物,懒得创建一个新类了。。。

    {
        for(int i = 0; i < 20; i++){
            addGood();
        }
    }
    //块,在构造方法之前自动运行,初始添加20个货物

    private Goods(){
    }

    public static Goods getInstance(){
        return goods;
    }

    //生产一个货物
    public synchronized String addGood(){  //使用synchronized锁定方法,这样调用这个方法的时候,Goods对象会被锁定,执行完后才能释放。

        goodList.add("货物" + num);
        num++;
        return "货物" + num;//返回生产的货物名字
    }

    //消费一个货物
    public synchronized String removeGood(){
        if(goodList.size() > 0) {
            String s = goodList.remove(0);
            return s;//返回消费的货物名字;
        }
        else{
            try {
                //wait的不是货物的线程,而是当前执行这个方法的对象所在线程(只有消费者调用这个方法)
                System.out.println("有人发现到货物" + num + "的时候没货啦,等在那里不动啦");

                //没有添加this.notifyAll();的情况下:
                //发现这句话运行了4遍后,4个消费者都没再买东西(因为消费者消费速度 > 生产者生产速度,还没来得及生产就卖完了),只有2个生产者还在生产。
                //程序卡在这里不再继续执行,称为:假死状态。
                //为了防止假死,在这个线程进入等待状态时,唤醒其他线程。
                //

                //notify
                this.notifyAll();  //----加上这句后,线程可以正常运行完毕。某个消费者发现没货后,过段时间还会再次尝试过购买(其他消费者发现没货了让他醒了)
                this.wait();
            } catch (Exception e) {
                e.printStackTrace();
            }
            return null;
        }
    }


}

 

 

 

posted @ 2019-10-10 18:06  不咬人的兔子  阅读(428)  评论(0编辑  收藏  举报