多线程带来便利的同时,也会带来麻烦
1,操作同一个共享资源的时候,会带来很多意想不到的麻烦。
就像卖票一样,如果不考虑多线程的环境,那肯定是没有问题的。
package secondSteps; /** * 卖票 * @author liugang * @create 2018/12/6 22:43 **/ public class SellTicket implements Runnable { private Integer ticketCount = 100; @Override public void run() { try { while (ticketCount>0){ sellTicket(); Thread.sleep(1000); } } catch (InterruptedException e) { e.printStackTrace(); } } private void sellTicket() { if (ticketCount>0){ ticketCount--; System.out.println("线程的名称:"+Thread.currentThread().getName()+"卖票 还剩"+ticketCount+"张"); }else{ System.out.println("票卖完了"); } } //如果不考虑多线程的环境,肯定不会出问题 }
public static void main(String[] args) { SellTicket ticket = new SellTicket(); Thread t1 = new Thread(ticket,"窗口1"); t1.start(); }
运行的状况:票是一张一张的少的。
现在开四个线程卖票
public static void main(String[] args) { SellTicket ticket = new SellTicket(); Thread t1 = new Thread(ticket,"窗口1"); Thread t2 = new Thread(ticket,"窗口1"); Thread t3 = new Thread(ticket,"窗口1"); Thread t4 = new Thread(ticket,"窗口1"); t1.start(); t2.start(); t3.start(); t4.start(); }
出现这种情况,是cpu高速切换,线程1,还没有执行完,在条件判断的时候,就切换到其他的线程。
多线程解决一个共享资源的占用问题是个头疼的问题
java提供了一定的解决办法。
操作共享资源的时候,不要竞争,一个一个来。比如,春节的时候在火车上厕所,一个人进去了把门锁了,方便之后开门,出来了。
给代码加个锁,就可以搞定这个问题。java提供了关键字synchronized,这个关键字代码块是要上锁的。那上什么锁呢,万物皆可superme
private Object obj = new Object();
private void sellTicket() { synchronized (obj){ if (ticketCount>0){ ticketCount--; System.out.println("线程的名称:"+Thread.currentThread().getName()+"卖票 还剩"+ticketCount+"张"); }else{ System.out.println("票卖完了"); } } }
对象是有一个标志位的,当前锁定这个标志位,另外一个线程进来了,发现标志位没改变,就动不了。
synchronized (this)//同步代码块, 锁 任何一个对象
锁自己,刚不刚,强不强,也一样的,万物皆可superme
还有可以把方法同步一样,把方法加个synchronized也一样,用哪种方法,就看自己的需求了。
代码块的好处:同步代码弄成最小的范围,提高效率。
同步方法就是 this,就是把当前对象锁了
静态方法锁,顾名思义,静态的方法锁,加个static
package secondSteps; /** * 卖票 * @author liugang * @create 2018/12/6 22:43 **/ public class SellTicket implements Runnable { private static Integer ticketCount = 100; private Object obj = new Object(); @Override public void run() { try { while (ticketCount>0){ sellTicket(); Thread.sleep(1000); } } catch (InterruptedException e) { e.printStackTrace(); } } private synchronized static void sellTicket() { //同步代码块 锁 任何一个对象 synchronized (SellTicket.class) { if (ticketCount > 0) { ticketCount--; System.out.println("线程的名称:" + Thread.currentThread().getName() + "卖票 还剩" + ticketCount + "张"); } else { System.out.println("票卖完了"); } } } //如果不考虑多线程的环境,肯定不会出问题 }
用static锁的是整个类,这样你new 出来的对象是没关系的,火车上4个人排队上一个厕所。
多个线程要同一个锁才可以。
注意:
1,同步代码块,他可以用任何一个对象作为锁
2,静态方法锁,锁的是整个类,所有对象过来都会阻塞,static是类级别,并不是某个对象。
3,synchronized方法,是锁的对象,这样是不行的。各所各的,是不一样的,是没有意思的。
线程的等待,线程的唤醒:
1,wait ----->导致获得这个锁的线程,阻塞等待,知道他被唤醒为止
2,notify ----->唤醒在等待这个锁的其他线程之一
3,notifyall ------->唤醒所有在等待的这个线程
package threeSteps; /** * 以这个类作为锁,让其他的类去等待,去唤醒 * @author liugang * @create 2018/12/6 23:30 **/ public class Message { private String msg; public Message(String msg) { this.msg = msg; } public Message() { } public String getMsg() { return msg; } public void setMsg(String msg) { this.msg = msg; } }
package threeSteps; /** * @author liugang * @create 2018/12/6 23:32 **/ public class Waiter implements Runnable{ private Message msg; public Waiter(Message msg) { this.msg = msg; } @Override public void run() { String name = Thread.currentThread().getName(); //当前线程,执行到了msg.wait()就会导致,持有这个锁的线程进行等待,一直到他被唤醒为止 synchronized (msg){ try { System.out.println(name+"等待"); msg.wait(); } catch (InterruptedException e) { e.printStackTrace(); } } } }
public static void main(String[] args) { Message msg = new Message("锁"); //同一个对象,同一个锁才行 Waiter waiter = new Waiter(msg); new Thread(waiter,"waiter").start(); Waiter waiter1 = new Waiter(msg); new Thread(waiter1,"waiter1").start(); Notifier notifier = new Notifier(msg); new Thread(notifier,"waiter").start(); }
运行结果如下:
这是因为我把notify改成notifyAll,唤醒所有了
package threeSteps; /** * 进行唤醒 * @author liugang * @create 2018/12/6 23:38 **/ public class Notifier implements Runnable{ private Message msg; public Notifier(Message msg) { this.msg = msg; } @Override public void run() { String name = Thread.currentThread().getName(); synchronized (msg){ msg.setMsg("唤醒线程工作"); // msg.notify(); msg.notifyAll(); } } }
wait运行到msg.wait()就卡死了,就一直等这了,就像我的联想笔记本动不动就卡死了,
好在有notify唤醒他,而我的笔记本就只能重启由我自己来唤醒他啦。
notify只能唤醒一个哟,另外一个只能一直卡死在那了。
notifyAll就唤醒所有,就像毛主席,是的