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; } } }