并发:同一个时间段内,交替执行
并行:同时执行(更快)
一个程序运行后至少有一个进程,一个进程中可以包含多个线程
单线程,就高速切换
8线程,就8个高速切换
分时调度
Java使用的为抢占式调度
main(主)线程
Thread
一.创建并启动多线程
1.定义Thread类的子类,并重写该类的run()方法
2.创建Thread子类的实例
3.调用线程对象的start()方法来启动该线程(开辟新的栈空间)
main和run并发运行****抢占式调度
二.创建线程二
1.实现Runnable接口的run方法
2.创实例
3.new Thread(对象名)
4.调start方法
好处:避免单继承局限,还可继承别人
解耦,代码共享
Thread类
start
getName
sleep
匿名内部类多线程
线程安全
访问了共享数据,出现卖票安全问题
1.同步技术
谁拿锁对象,谁运行
锁:this
synchronized (任意对象){
//同步的代码
}
2.同步方法()
public synchronized void method(){
}
static锁对象 是 .class
3.Lock锁
更广泛
Lock lock=new ReentrantLock();
lock()
unlock()
Waiting(无限等待)
notify唤醒
wait等待
public class Demo02WaitAndNotify {
public static void main(String[] args) {
//创建锁对象,保证唯一
Object obj = new Object();
// 创建一个顾客线程(消费者)
new Thread(){
@Override
public void run() {
//一直等着买包子
while(true){
//保证等待和唤醒的线程只能有一个执行,需要使用同步技术
synchronized (obj){
System.out.println("顾客1告知老板要的包子的种类和数量");
//调用wait方法,放弃cpu的执行,进入到WAITING状态(无限等待)
try {
obj.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
//唤醒之后执行的代码
System.out.println("包子已经做好了,顾客1开吃!");
System.out.println("---------------------------------------");
}
}
}
}.start();
// 创建一个顾客线程(消费者)
new Thread(){
@Override
public void run() {
//一直等着买包子
while(true){
//保证等待和唤醒的线程只能有一个执行,需要使用同步技术
synchronized (obj){
System.out.println("顾客2告知老板要的包子的种类和数量");
//调用wait方法,放弃cpu的执行,进入到WAITING状态(无限等待)
try {
obj.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
//唤醒之后执行的代码
System.out.println("包子已经做好了,顾客2开吃!");
System.out.println("---------------------------------------");
}
}
}
}.start();
//创建一个老板线程(生产者)
new Thread(){
@Override
public void run() {
//一直做包子
while (true){
//花了5秒做包子
try {
Thread.sleep(5000);//花5秒钟做包子
} catch (InterruptedException e) {
e.printStackTrace();
}
//保证等待和唤醒的线程只能有一个执行,需要使用同步技术
synchronized (obj){
System.out.println("老板5秒钟之后做好包子,告知顾客,可以吃包子了");
//做好包子之后,调用notify方法,唤醒顾客吃包子
//obj.notify();//如果有多个等待线程,随机唤醒一个
obj.notifyAll();//唤醒所有等待的线程
}
}
}
}.start();
}
}
线程通信
notify唤醒
wait等待 要用同一个锁
Java的线程池
// 创建线程池对象
ExecutorService service = Executors.newFixedThreadPool(2);//包含2个线程对象
// 创建Runnable实例对象
MyRunnable r = new MyRunnable();
// 从线程池中获取线程对象,然后调用MyRunnable中的run()
service.submit(r);
lambda
// 匿名内部类
Runnable task = new Runnable() {
@Override
public void run() { // 覆盖重写抽象方法
System.out.println("多线程任务执行!");
}
};
new Thread(task).start();
变成
new Thread(() -> System.out.println("多线程任务执行!")).start(); // 启动线程
函数式接口中要求:一个抽象方法
() 里面填参数
->
{}方法体
public interface Calculator {
int calc(int a, int b);
}
public class Demo08InvokeCalc {
public static void main(String[] args) {
// Lambda【标准格式】调用invokeCalc方法来计算120+130的结果
invokeCalc(120, 130, (int a, int b) -> {
return a + b;
});
}
}
private static void invokeCalc(int a, int b, Calculator calculator) {
int result = calculator.calc(a, b);
System.out.println("结果是:" + result);
}
}