1、多线程
历程:当前正在运行的程序,即一个应用程序在内存中的执行区域。
线程:历程中的一个执行控制单元。一个历程可以有一个线程,也可以有多个线程。
单线程:安全性高然则效率低。多线程:安全性低然则效率高。
CPU执行线程具有随机性。
多线程的实现方式1 :Thread 类。
写一个子类,继续 Thread 类。
在子类中重写 Thread 类的 run 方式,内容是线程的操作内容。
确立线程实例。
使用 .start() 方式启动线程。
public class MyThread extends Thread {
@Override
public void run(){
System.out.println("线程");
System.out.println(getName());
}
}
MyThread mt = new MyThread();
mt.setName("线程A");
mt.start();
Thread 类中的方式:
String getName():获取线程的名字。
void setName(String name):改变线程名字。
static Thread currentThread():返回对当前正在执行的线程工具的引用。
static void sleep(long millis):将线程休眠一段时间。
主方式是单线程的。
多线程的实现方式2 :实现 Runnable 接口。
写一个子类,实现 Runnable 接口。
在子类中重写 run 方式,内容是线程的操作内容。
确立线程实例,并将其作为参数传入 Thread 工具。
使用 .start() 方式启动线程。
public class MyThread implements Runnable {
@Override
public void run(){
System.out.println("线程");
System.out.println(Thread.currentThread().getName());
}
}
MyThread mt = new MyThread(); // 可以只确立一个,然则所有 Thread 工具会共享成员变量
Thread t1 = new Thread(mt);// 将实现的接口的工具作为参数传入
t1.setName("线程A");
t1.start();
Thread t2 = new Thread(mt);
t2.setName("线程B");
t2.start();
为什么多线程需要第二种方式的接口实现:由于 Java 中单一继续的缘故原由,继续了 Thread 类就无法继续其他类。
线程的生命周期:
新建:确立线程工具。
停当:具备了执行条件,但没有执行权力。
运行:具备了执行权力。
殒命:作为垃圾接纳。
守候与叫醒:void wait():使当前线程守候。void notify():叫醒守候的线程。需要使用锁工具挪用,挪用线程被叫醒后先进入停当状态。
2、同步
多个线程共享同一个数据而且并发接见共享的数据,可能会失足。
synchronized关键字:示意同步,可以修饰代码块和方式。被修饰的代码块和方式一旦被某个线程接见,则直接锁住,其他线程无法接见。
同步代码块:
synchronized(锁工具){
// 执行代码
}
同步方式:
private synchronized void method(){
// 执行代码
}
锁工具需要被所有的线程所共享,非静态同步方式的锁工具默以为 this ,静态同步方式的锁工具默以为当前类的字节码工具。
同步:安全性高,效率低。
3、分票案例
public class Ticket implements Runnable{
int tickets = 100;
Object obj = new Object();
@Override
public void run(){
while(true){
method();
}
}
public synchronized void method(){
if(tickets > 0){
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + ":" + tickets--);
}
}
}
public class Demo {
public static void main(String[] args) {
Ticket t = new Ticket();
Thread td1 = new Thread(t);
td1.setName("A");
Thread td2 = new Thread(t);
td2.setName("B");
Thread td3 = new Thread(t);
td3.setName("C");
td1.start();
td2.start();
td3.start();
}
}
3、Stream流
用于对聚集和数组举行操作,用于JDK1.8之后。
流式头脑:确立生产线,根据生产线来生产产物。
Stream 流是一个聚集元素的函数模子,不是聚集也不是数据结构,自己不存储任何元素。
由于 Lamda 表达式的延迟特征,只有最后一步执行时,整个模子才会按序依此执行。
Stream 操作的特征:
pipelining:中心操作都返回流工具自己,多个操作可以串联成一个管道。
内部迭代。
属于管道流,只能被消费(使用)一次。第一个 Stream 流挪用方式,数据就会传到下一个流,第一个流就不能再使用了。
Stream 操作步骤:
获取数据源、数据转换、执行操作。
每次转换原有的 Stream 流工具稳定,返回一个新的 Stream 工具。
获取 Stream 流:
所有的 Collection 聚集都可以通过stream()方式获取流。
对于 Map 聚集,可以将其键值对(entrySet)通过stream()方式获取流。
通过 Stream 中的of(T... value)静态方式方式将数组转换为Stream流。
Stream 流中的常用方式。
延迟方式:返回值仍然是 Stream 接口自身的方式,可以链式挪用。
filter(Predicate super T> predicate):传入的是 Predicate 接口,将一个流转换为另一个流(过滤)。好比只将以A开头的字符串通报到下一个流。
map(Function super T, extends R> mapper):传入的是 Function 接口,将一个流转换为另一个流(映射)。好比将String类型的整数转换为Integer类型。
limit(long maxSize):截取方式,只取前几个元素传入下一个流。
skip(long n):跳过前几个元素,将后边的元素传入下一个流。
concat(Stream extends T> a, Stream extends T> b):静态方式,将两个流合并为一个流。
终结方式:返回值不再是 Stream 接口自身的方式,不可以链式挪用。
void forEach(Consumer super T> action):传入的是 Consumer 接口,用来遍历流中的数据。
long count():获取元素花样。
4、方式引用
用于简化 Lamda 表达式。
适用情形:
Lamda 表达式中的代码实现,已经有地方存在相同的实现,则可以直接挪用这个实现。
条件是,所挪用的工具和方式都是以及存在的。
示例:
//函数式接口
public interface Printable {
void print(String s);
}
//方式以函数式接口为参数
public static void printString(Printable p) {
p.print("Hello");
}
//对于 Lamda 表达式
printString((s)->{
System.out.println(s);
});
//方式引用优化
printString(System.out::println);
由于 System.out 工具是自动确立好的,所有可以直接让 System.out 中的 println 方式取代 Lamda 表达式。
::为引用运算符,其所在的表达式被称为方式引用。
Lamda 表达式中通报的参数一定是方式引用中的谁人方式可以吸收的类型。
通过工具名引用成员方式:
工具名和成员方式都是已经存在的,否则要先确立工具。
通过工具名::成员方式来引用。
通过类名引用静态方式:
类名和静态方式都是已经存在的,不需要实例化工具。
通过类名::静态方式来引用。
通过 super 引用父类成员方式:
存在父类和父类中存在此方式,不需要实例化父类工具。
通过super::成员方式来引用。
通过 this 引用本类成员方式:
本类中存在此方式。
通过this::成员方式来引用。
类的组织器引用:
Lamda 表达式返回的是,通过组织方式一个新确立的工具。
通过类名::new来引用。
数组的组织器引用:
返回的是一个新确立的数组。
通过数据类型[]::new来引用。
iwehdio的博客园:https://www.cnblogs.com/iwehdio/
原文链接:https://www.cnblogs.com/iwehdio/p/12896615.html
本站声明:网站内容来源于网络,若有侵权,请联系我们,我们将及时处理。