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接口
- 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{ @Override public Integer call() throws Exception { System.out.println("come in here"); return 1111; } } public class CallableDemo { public static void main(String[] args) throws ExecutionException, InterruptedException { FutureTask futureTask = new FutureTask(new MyThread()); new Thread(futureTask,"A").start(); System.out.println(futureTask.get()); } }
使用FutureTask执行任务
需要注意的几点,在使用FutureTask时如果立即get会阻塞只到线程得到结果才能继续向下执行,如果不需要立刻得到结果可以在get钱添加其他业务逻辑。示例:
package ThreadLocal; import java.util.concurrent.Callable; import java.util.concurrent.ExecutionException; import java.util.concurrent.FutureTask; class MyThread implements Callable8锁{ @Override public Integer call() throws Exception { System.out.println("come in here"); return 1111; } } public class CallableDemo { public static void main(String[] args) throws ExecutionException, InterruptedException { FutureTask futureTask = new FutureTask(new MyThread()); new Thread(futureTask,"A").start(); System.out.println(futureTask.get()); } }
现在有一个手机对象,拥有两个功能都被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



