一,线程间的协作,如何来实现?
1,轮询:难以保证及时性,资源开销很大
2,等待和通知
等待和通知的标准范式:
等待方:
要去获取对象的锁,
然后在循环里判断条件是否满足,不满足调用wait方法。
条件满足,执行业务逻辑
通知方:
获取对象的锁
改变条件
通知所有等待在对象的线程
3,方法:
wait():等待着获取对象的锁
wait(1000):等待超时,超过一定时间就不等待了。
notify:通知一个线程
notifyAll:通知所有等待同一把锁的线程
二,join()方法
1,面试问题:有线程A和线程B,如何保证线程B一定在线程A执行完以后才执行?
方法一:join()
方法二:countDownLatch
解释:如果线程A执行了线程B的join方法,线程A必须等待线程B执行完了以后,线程A才能继续自己的工作。
示例代码:掉用join()方法,可以让该线程优先执行
/** * 演示join()方法 */ public class UseJoin2 { static class JumpQueue extends Thread{ @Override public void run() { for (int i = 0; i <5 ; i++) { System.out.println("当前线程正在执行步骤"+i); try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } } } } public static void main(String[] args) { System.out.println("进入main方法------>"); JumpQueue jumpQueue = new JumpQueue(); jumpQueue.setName("joinThread"); jumpQueue.start(); //jumpQueue.join()方法:会让jumpQueue线程在main线程之前执行 try { jumpQueue.join(); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("main线程开始处理业务逻辑"); try { Thread.sleep(500); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("main线程处理完业务逻辑了"); } }
三,yield(),sleep(),wait(),notify()等方法对锁的影响
线程在执行yield()以后,持有的锁是不释放的
sleep()方法调用以后,持有的锁是不释放的
wait():在调用wait()方法之前,必须要持有锁。在调用wait()方法以后。锁就会被释放(虚拟机进行释放),当wait方法返回时,线程会重新持有锁
notify():在调用之前,必须要持有锁。调用notify()方法本身是不会释放锁的,只有synchronized代码块执行完才释放锁
notifyAll():同notify()
比如:public synchronized void changeKm(){
this.km = 101;
notify();//当执行完这行代码时,此时还没有释放锁。
System.out.println("处理业务逻辑"); //执行完这一行代码后,才释放锁。
}
1,示例代码:sleep()方法调用以后,持有的锁识是不释放的
/** * 验证sleep()方法,线程休眠时不会释放锁 * 当A线程拿到锁后,然后进行sleep休眠。其他线程是拿不到锁的,只能等待 */ public class SleepLock { private Object lock = new Object(); //会休眠的线程类 private class ThreadSleep extends Thread{ @Override public void run() { String threadName = Thread.currentThread().getName(); //尝试去拿锁 System.out.println(threadName + " try to take the lock"); try { synchronized (lock){ System.out.println(threadName + " is taking the lock"); //该线程拿到锁后,休眠5秒 Thread.sleep(5000); System.out.println("Finish the work: "+ threadName); } }catch (InterruptedException e){ } } } //不会休眠的线程类 private class ThreadNotSleep extends Thread{ @Override public void run() { String threadName = Thread.currentThread().getName(); //尝试去拿锁 System.out.println(threadName + " try to take the lock time = "+System.currentTimeMillis()); synchronized (lock){ System.out.println(threadName + " taking the lock time = "+ System.currentTimeMillis()); System.out.println("Finish the work"+threadName); } } } public static void main(String[] args) { SleepLock sleepLock = new SleepLock(); //会休眠的线程 Thread threadSleep = sleepLock.new ThreadSleep(); threadSleep.setName("threadSleep"); //不会休眠的线程 Thread threadNotSleep = sleepLock.new ThreadNotSleep(); threadNotSleep.setName("threadNotSleep"); threadSleep.start(); threadNotSleep.start(); } }
2,示例代码:wait()方法调用后,会释放锁
public class ThreadDomain31 extends Thread{ private Object lock; public ThreadDomain31(Object object){ this.lock = object; } @Override public void run() { try { synchronized (lock) { System.out.println(Thread.currentThread().getName() + " Begin wait()"); lock.wait(); System.out.println(Thread.currentThread().getName() + " End wait"); } } catch (InterruptedException e) { e.printStackTrace(); } } }
public class Test { public static void main(String[] args) { /** * 输出: * Thread-0 Begin wait() Thread-1 Begin wait() wait()会释放锁,不然线程2根本进不去 */ Object lock = new Object(); ThreadDomain31 mt0 = new ThreadDomain31(lock); ThreadDomain31 mt1 = new ThreadDomain31(lock); mt0.start(); mt1.start(); } }
3,经典的生产者消费者模式演示 :wait()/notify()方法的使用
/** * 产品 */ public class Product { private String name; private boolean flag = false; //生产方法 public synchronized void set(String name){ System.out.println(Thread.currentThread().getName()+"准备生产数据....."); //如果有值就等待 if (this.flag){ try { System.out.println("数据还没有被消费,生产者进行等待"); this.wait(); } catch (InterruptedException e) { e.printStackTrace(); } } System.out.println(Thread.currentThread().getName()+"开始生产数据..."); Random random = new Random(); int second = random.nextInt(5000); try { Thread.sleep(second); } catch (InterruptedException e) { e.printStackTrace(); } this.name = name; this.flag = true; System.out.println(Thread.currentThread().getName()+"生产数据完成..."+",一共花费了"+second+"ms"); System.out.println(Thread.currentThread().getName()+"通知消费者去消费数据"); this.notify();//通知消费者去消费 } //消费方法 public synchronized void get(){ System.out.println(Thread.currentThread().getName()+"准备消费数据....."); //如果没有等待 if (!this.flag){ try { System.out.println("数据还没有被生产,消费者进行等待"); this.wait(); } catch (InterruptedException e) { e.printStackTrace(); } } System.out.println(Thread.currentThread().getName()+"开始消费数据..."); Random random = new Random(); int second = random.nextInt(5000); try { Thread.sleep(second); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(Thread.currentThread().getName()+"消费数据完成..."+"name:"+name+""+",一共花费了"+second+"ms"); this.flag = false; System.out.println(Thread.currentThread().getName()+"通知生产者去生产数据"); this.notify();//通知生产者去生产 } }
/** * 生产者 */ public class Producer implements Runnable{ private Product student; public Producer(Product student){ this.student = student; } @Override public void run() { while (true){ student.set("产品名称"); } } }
/** * 消费者 */ public class Consumer implements Runnable{ private Product student; public Consumer(Product student){ this.student = student; } @Override public void run() { while (true){ student.get(); } } }