6.14 多线程【java.lang】
应用程序:静态指令集。 例如:QQ、百度云盘。。。
进程:应用程序当运行时。开辟进程【内存】QQ后台进程
线程:进程中一个程序控制流
轻量级的进程【不用开辟内存】,CPU最小调度单元,进程中包含多个线程,这些线程协调工作,并发运行,即为多线程。
好处:
提高代码的运行效率,CPU调度效率高。
6.14.1 多线程的创建【※】
1. 继承java.lang.Thread
2. 实现接口 java.lang.Runnable
3. 线程池 java.util.concurrent.Callable
6.14.2 Thread类
public class Thread extends Object implements Runnable{
}
属性:
MAX_PRIORITY 最高优先级 10
MIN_PRIORITY 最低 1
NORM_PRIORITY 默认 5
构造:
new Thread() ;
new Thread(Runnable target) ;
方法:
方法名 | 含义 | 参数 | 返回值 |
run() | 线程体: 该线程内容,不能直接调用run() | void | |
start() | 线程启动,一个线程只需启动1次,就绪,自动调用run() | ||
currentThread() | 获得当前正在运行的线程 | Thread | |
getName() | 获得线程名 | ||
setName() | 设置线程名 | ||
setPriority(优先级数字) | 设置线程的优先级【1-10】 | 优先级 | void |
getPriority() | 获得优先级 | int | |
static sleep(毫秒) | 线程休眠 throws InterruptedException | 休眠时间 | |
yield() | 线程暂停 |
public class MyThread extends Thread{
public MyThread() {
super();
// TODO Auto-generated constructor stub
}
public MyThread(String name) {
super(name);
// TODO Auto-generated constructor stub
}
@Override
public void run() {
for (int i = 1; i <= 20; i++) {
System.out.println(Thread.currentThread().getName() + ":" + i);
}
}
}
public class TestThread {
public static void main(String[] args) {
System.out.println("主线程");
MyThread t1 = new MyThread("甲线程");
MyThread t2 = new MyThread("乙线程");
t1.start();
t2.start();
}
}
售票练习:
public class TicketThread extends Thread{
private int tickets = 100;
@Override
public void run() {
while(true) {
//线程体
if(tickets == 0) {
System.out.println("售空了");
break;
}
else
System.out.println(Thread.currentThread().getName() + "售出第" + (100 - --tickets) + "张票");
}
}
}
public class Test {
public static void main(String[] args) {
System.out.println("开放售票窗口");
TicketThread t1 = new TicketThread("窗口1");
//t1.setName("窗口1");
TicketThread t2 = new TicketThread();
t2.setName("窗口2");
t1.start();
t2.start();
}
}
sleep和yield,wait:
sleep() 线程调用后,线程进入挂起,让出cpu给其他任意有需要的线程,当休眠时间到了,该线程进入就绪状态等待CPU的重新调度
yield() 线程暂停,让出CPU给比它优先级高的线程,直接进入就绪状态,一旦没有更高优先级,立刻抢占CPU。
wait() Object的方法,线程等待,需要手动唤醒
join() 加入线程,start()后设置,其他线程等他执行完再恢复
线程休眠:
public class WashigThread extends Thread{
@Override
public void run() {
for (int i = 1; i <= 5; i++) {
System.out.println("清洗第" + i + "个杯子");
try {
Thread.sleep(1500);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println("第" + i + "个杯子清洗完成");
}
}
}
public class BoilThread extends Thread{
@Override
public void run() {
System.out.println("开始烧水.......");
try {
Thread.sleep(10000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println("水烧开了.....");
}
}
public class TestThread {
public static void main(String[] args) {
BoilThread b = new BoilThread();
WashigThread w = new WashigThread();
b.start();
w.start();
System.out.println("客人来啦");
}
}
6.14.3 线程的状态
开始状态
就绪状态
运行状态
阻塞状态【挂起】
结束状态
![](https://i-blog.csdnimg.cn/blog_migrate/9ae59ec70770c0e615106aeb94598de2.png)
6.14.4 Runnable接口方式
public interface Runnable{
void run();
}
1.实现类实现接口
2.匿名内部类
3.lambda
public class TicketThread2 implements Runnable{
private int tickets = 100;
@Override
public void run() {
while(true) {
//线程体
if(tickets == 0) {
System.out.println("售空了");
break;
}
else
System.out.println(Thread.currentThread().getName() + "售出第" + (100 - --tickets) + "张票");
}
}
}
测试:
public class Test2 {
public static void main(String[] args) {
TicketThread2 w1 = new TicketThread2();
Thread t1 = new Thread(w1);
t1.start();
TicketThread2 w2 = new TicketThread2();
Thread t2 = new Thread(w2);
t2.start();
}
}
匿名内部类写法:
new Thread(new Runnable() {
private int tickets = 100;
@Override
public void run() {
while(true) {
//线程体
if(tickets == 0) {
System.out.println("售空了");
break;
}
else
System.out.println(Thread.currentThread().getName() + "售出第" + (100 - --tickets) + "张票");
}
}
}).start();
lambda写法:
new Thread(()->{
int tickets = 100;
while(true) {
//线程体
if(tickets == 0) {
System.out.println("售空了");
break;
}
else
System.out.println(Thread.currentThread().getName() + "售出第" + (100 - --tickets) + "张票");
}
}).start();
6.14.5 线程同步
线程同步,线程安全,当A线程和B线程有共享数据资源【临界资源】时,A线程对共享数据资源访问时,B线程无法操作。造成程序执行效率低。速度慢。
线程不同步,不安全,效率高,速度快,控制线程运行
1. 加锁
synchronized
lock()
2. 避免临界资源
同步的两种形态:
1. 同步块
synchronized(临界资源){
锁定临界数据
}
2. 同步方法
public synchronized 返回值 方法(){
}
示例:
@Override
public void run() {
synchronized (card) {
//10次 一次1000 当前余额
for (int i = 1; i <= 10; i++) {
card.setMoney(card.getMoney() + 1000);
//显示
System.out.println(Thread.currentThread().getName() + "存入1000元,当前余额:" + card.getMoney());
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
改写:
public class TestCard {
public static void main(String[] args) {
BankCard card = new BankCard(5000);
Thread t1 = new Thread(() -> {
// 10次 一次1000 当前余额
for (int i = 1; i <= 10; i++) {
synchronized (card) {
card.setMoney(card.getMoney() + 1000);
// 显示
System.out.println(Thread.currentThread().getName() + "存入1000元,当前余额:" + card.getMoney());
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
});
Thread t2 = new Thread(() -> {
// 10次 一次1000 当前余额
for (int i = 1; i <= 10; i++) {
synchronized (card) {
if (card.getMoney() == 0) {
System.out.println("余额不足");
} else {
card.setMoney(card.getMoney() - 1000);
// 显示
System.out.println(Thread.currentThread().getName() + "取1000元,当前余额:" + card.getMoney());
}
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
});
t1.setName("齐齐");
t2.setName("玛丽");
t1.start();
t2.start();
}
}
思考: 目前所学哪些类/接口 线程安全和不安全?
线程安全 不安全:
StringBuffer StringBuilder
Vector ArrayList /LinkedList
Hashtable HashMap
死锁现象:
两个线程,A线程占用B线程需要的资源不释放, 同时,B线程占用的A线程需要的资源也不释放,死锁。
6.14.6 线程通信
多个线程并发运行时,线程直接互相发送信号,以多线程的高效执行。
实现机制:
wait() 线程等待
notify()
notifyAll() 唤醒
经典案例:生产者 消费者模型
![](https://i-blog.csdnimg.cn/blog_migrate/12c1e94af52fa47e2882b6b239f6cf08.png)
当生产者生产过多仓库库存, 线程等待,唤醒消费者消耗产品
当消费者发现库存清0 ,线程等待,唤醒生产者生产产品
/**
仓库
*/
public class Clerk {
//产品
private int product;
public Clerk(int product) {
super();
this.product = product;
}
/**
* 生产
*/
public synchronized void produce() {
if(product >= 20) {
//别生产
try {
wait();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}else {
product ++;
System.out.println(Thread.currentThread().getName() + "生产产品,当前库存:" + product);
notifyAll();
}
}
/**
* 消耗
*/
public synchronized void consume() {
if(product <= 0) {
try {
wait();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}else {
product --;
System.out.println(Thread.currentThread().getName() + "消耗产品,当前库存:" + product);
notifyAll();
}
}
}
/**
生产者线程
*/
public class ProductThread implements Runnable{
private Clerk c;
public ProductThread(Clerk c) {
super();
this.c = c;
}
@Override
public void run() {
while(true) {
c.produce();
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
/**
消费者
*/
public class ConsumerThread implements Runnable{
private Clerk c;
public ConsumerThread(Clerk c) {
super();
this.c = c;
}
@Override
public void run() {
while(true) {
c.consume();
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
public class Test {
public static void main(String[] args) {
Clerk c = new Clerk(0);
//生产者
new Thread(new ProductThread(c),"生产者1").start();
new Thread(new ProductThread(c),"生产者2").start();
//消费者
new Thread(new ConsumerThread(c),"消费者").start();
}
}
6.14.7 线程池
线程池: 缓冲N个即将运行的线程为多个任务提供服务,减少每次的创建以及销毁开销,达到线程高效利用。
![](https://i-blog.csdnimg.cn/blog_migrate/7342ff91c84902863d3824c21e908bf1.png)
使用:
Executors 工厂类 创建线程池的
ExecutorService 线程池提供服务的对象 ,接收任务
提交任务
submit(Runnable r) // lang run() 无返回值 无异常抛出
submit(Callable c) // util call() 有返回值
shutdown() 不再接收任务
Future 获得结果的接口
get();
线程池:
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
public class TestPool {
public static void main(String[] args) {
//创建线程池
ExecutorService service = Executors.newFixedThreadPool(3);
//提交任务1
Future<Integer> res1 = service.submit(new Callable<Integer>() {
@Override
public Integer call() throws Exception {
int sum = 0;
for (int i = 1; i <= 50; i++) {
sum += i;
}
return sum;
}
});
Future<Integer> res2 = service.submit(()->{
int sum = 0;
for (int i = 51; i <= 100; i++) {
sum += i;
}
return sum;
});
try {
System.out.println(res1.get() + res2.get());
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (ExecutionException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
service.shutdown();
}
}
第七章 JDK8+新特性
概述新特性:
jdk8 和jdk5一样,是里程碑版本,2014年发布,新特性。
![](https://i-blog.csdnimg.cn/blog_migrate/1545952de95373d59d689873f1be89e7.png)
7.1 接口的改变
// 非抽象的默认方法,所有实现类相同,无序重写的
public interface Fly {
//起飞
void takeOff();
//着陆
//默认方法
default void land() {
System.out.println("着陆了");
}
}
//接口自己使用的静态方法
public interface Fly {
//静态方法
static void tool() {
System.out.println("飞行工具使用");
}
}
7.2 String新增
join(”连接符“,数组)
split("分隔符")
public static String hide(String ip) {
String[] a = ip.split("\\.");
a[a.length - 1 ] = "*";
return String.join(".", a);
}
7.3 lambda
特殊的匿名内部类,语法更加简单。
函数式接口 对象 = (参数变量1,参数变量2...) ->{
//方法体;
};
函数式接口的特点:
1. 可以有多个非抽象方法,但有且只要一个抽象方法
2. 一般用于标志,起到编译时的规范作用,添加注解: @FunctionalInterface
表达式特点:
1.参数列表类型无需指定,自动推算
2.没有参数的只需()
3.如果只要一个参数,可省略()
4.返回值只要一句话,return {}可以省略
7.4 常用的函数式接口
![](https://i-blog.csdnimg.cn/blog_migrate/1e540153c144d823faac6e6931eca2ec.png)
public class TestLa2 {
public static void main(String[] args) {
//消费型接口
Consumer<String> c = t -> System.out.println("该名字长度:" + t.length());
c.accept("jackson");
//1-16一个
//供给型
Supplier<Integer> s = () -> (int)(16 * Math.random() + 1);
System.out.println(s.get());
//函数式
Function<String, Integer> f = t -> t.length();
System.out.println(f.apply("jack"));
//断言接口
Predicate<String> p = n -> n.endsWith(".txt");
System.out.println(p.test("E:\\1.txt"));
}
}
7.5 Stream
Stream作用简化对数组以及集合的操作【筛选,求和,过滤,排序,最大值,计数....】
原理:
![](https://i-blog.csdnimg.cn/blog_migrate/a98d97f93c8c84b4904af722083878f8.png)
//1 转化成Stream
集合对象.stream()
//2. 案例
public class TestStream {
public static void main(String[] args) {
List<Integer> list = Arrays.asList(10,45,10,67,36,90,45);
list = list.stream().distinct().sorted().collect(Collectors.toList());
list.forEach(t -> System.out.println(t));
}
}