Lambda表达式是jdk1.8出现的编码方式,主要作用是让代码更加简洁,也可以提高代码的内聚,减少代码中不必要的实现类。
如何写一个java实现类
interface InterFaceDemo{ int add(); default int demo(int x ,int y){ return x+y; }}public class LambdaExpress { public static void main(String[] args) { InterFaceDemo demo = ()->{ System.out.println(); return 1; }; }}
函数式接口:java8新特性的一种,用于标识接口。一般把这样的接口用于链式编程中。
多线程编程 1.概念接口中的静态方法:与普通类中的静态方法没有区别,调用方式:接口.方法名直接使用
1.多线程编程方法:在高内聚低耦合的前提下,线程操作资源类。
2.多线程编程流程:判断——>干活——>通知
3.多线程编程中需要注意的问题:虚假唤醒,判断标志变量只能使用while不能使用if。
原因:if只会做一次判断,而while会循环判断直到变量值变为期望值。
4.标志位移,一般用于做为判断条件。
资源类资源类=实例变量+实例方法
public class Ticket { private int number = 30; Lock lock = new ReentrantLock(); public void sale(){ lock.lock(); try { if ( number > 0){ System.out.println(Thread.currentThread().getName()+"t卖出第:"+(number--) +"t 还剩下:"+number ); } } catch (Exception e) { e.printStackTrace(); } finally { lock.unlock(); } }}
操作一般是指线程使用资源类中的方法打到某种目的。
线程通常情况下采用匿名内部类的方式定义线程
//普通版本new Thread(new Runnable() { @Override public void run() { for (int i = 0; i < 40; i++) { ticket.sale(); } } },"A").start();//Lambda 表达式版本new Thread(()->{for (int i = 0; i < 40; i++) ticket.sale(); },"B").start();
JDK1.8之后消费者和生产者写法的区别主要是添加了lock与condition来帮助加锁与唤醒线程。
private int number = 0; private Lock lock = new ReentrantLock(); private Condition condition = lock.newCondition();// 旧版// public synchronized void increase()throws InterruptedException{// if (number!=0){// this.wait();// }// number++;// System.out.println(Thread.currentThread().getName()+"t"+number);// this.notifyAll();// } public void increase()throws InterruptedException{ while (number!=0){ condition.await(); } number++; System.out.println(Thread.currentThread().getName()+"t"+number); condition.signalAll(); }
使用新方法的原因能够实现线程间的精准通知。
package JUC;import java.util.concurrent.locks.Condition;import java.util.concurrent.locks.Lock;import java.util.concurrent.locks.ReentrantLock;// A 五次 B 十次 C 15次的顺序 十轮class ShareResource{ // 标志位 private int number = 1; private Lock lock = new ReentrantLock(); private Condition conditionA = lock.newCondition(); private Condition conditionB = lock.newCondition(); private Condition conditionC= lock.newCondition(); public void print(int count){ lock.lock(); try { //判断 if (count == 5) { while (number != 1) { conditionA.await(); } conditionAwait(5,conditionB,2); } if (count == 10) { while (number != 2) { conditionB.await(); } conditionAwait(10,conditionC,3); } if (count == 15) { while (number != 3) { conditionC.await(); } conditionAwait(15,conditionA,1); } } catch(Exception e){ e.printStackTrace(); } finally{ lock.unlock(); } } public void conditionAwait(int count,Condition condition,int value) throws InterruptedException { for (int i = 0; i < count; i++) { System.out.println(Thread.currentThread().getName() + " /t" + "现在是第" + i + "次打印"); } number = value; condition.signal(); }}public class ThreadOrderAccess { public static void main(String[] args) { ShareResource shareResource = new ShareResource(); new Thread(()->{ for (int i = 0; i <10 ; i++) { shareResource.print(5); } },"A").start(); new Thread(()->{ for (int i = 0; i < 10; i++) { shareResource.print(10); } },"B").start(); new Thread(()->{ for (int i = 0; i < 15; i++) { shareResource.print(15); } },"C").start(); }}
多线程中创建多线程的几种方式 继承Thread类实现Runnabble接口实现Callable接口 Runnable与Callable有什么区别 Callable有返回值Runnable没有Callable抛出异常,Runnable没有方法命 Callable叫call Runnable叫run通过Callable创建线程的一般方法:
package ThreadLocal;import java.util.concurrent.Callable;import java.util.concurrent.ExecutionException;import java.util.concurrent.FutureTask;class MyThread implements Callable
使用FutureTask执行任务
需要注意的几点,在使用FutureTask时如果立即get会阻塞只到线程得到结果才能继续向下执行,如果不需要立刻得到结果可以在get钱添加其他业务逻辑。示例:
package ThreadLocal;import java.util.concurrent.Callable;import java.util.concurrent.ExecutionException;import java.util.concurrent.FutureTask;class MyThread implements Callable
现在有一个手机对象,拥有两个功能都被synchronize方法修饰:1.短信发送,2.发送邮件
标准访问,请问先打印邮件还是短信? 先打印邮件后打印短信
邮件方法暂停4秒钟,请问先打印邮件还是短信?
新增普通方法hello( ),先打印邮件还是hello?
两部手机,请问先打印邮件还是短信?
两个静态同步方法,一部手机,先打印邮件还是短信
两个静态同步方法,两部手机,请问先打印邮件还是短信
一个普通同步方法,一个静态同步方法,一部手机,请问先打印邮件还是短信?
一个普通同步方法,一个静态同步方法,两部手机,请问先打印邮件还是短信?
8锁问题的回答:
Synchronize实现同步的基础:java中的对象都可以作为锁
具体表现为以下三种形式
1.对于普通同步方法:锁是当前对象
2.对于静态同步方法:锁是当前对象类的Class对象
3.对于同步方法块:锁是synchronize括号中配置的对象
一个对象(资源类)中如果有多个方法被synchronize修饰,只要其中一个被加锁的方法被使用,那么其他线程如果也要使用被加锁的方法只能等待。
普通方法(不加synchronize的方法)不受synchronize影响,即便当前对象被锁也能正常访问。
使用同一个类创建出来的对象虽然功能相同,但他们是两个不同的锁。
静态同步方法锁的是类本身,而不是当前对象。
所有非静态同步方法的锁对象都是对象本身:this
同步方法、同步方法块线程访问普通方法锁的是实例对象自身。调用带有synchronize的方法需要获得锁对象,当没有获得锁对象时,线程会因为没有对于的锁对象而进入等待状态。因为锁对象是对象本身,如果创建新的实例对象(new一个对象)还是能够通过新的实例对象调用同步方法的。
非线程安全的类 List 主要表现:多线程环境下回发生ConcurrentModificationException
解决方法:
1.使用synchronize或lock进行同步操作
2.使用数组中的Vector
3.使用CopyOnWriteArrayList
添加元素的过程:将原容器的数据复制出来用一个新的容器装载,当向新容器中添加完成之后,再将原容器的引用指向新的容器
好处:因为读和写是在不同的容器中,所以能够保证在元素添加完成前不管怎么读数据都是一致的。
源码:
public boolean add(E e) { final ReentrantLock lock = this.lock; lock.lock(); try { Object[] elements = getArray(); int len = elements.length; Object[] newElements = Arrays.copyOf(elements, len + 1); newElements[len] = e; setArray(newElements); return true; } finally { lock.unlock(); } }
Map解决Map线程不安全的方法:ConcurrentHashMap
Set 多线程下发生:ConcurrentModificationException
解决方法:CopyOnWriteArraySet