1.什么是进程? 应用程序的一个运行实例 包含程序所需要的资源的内存区域,是操作系统进行资源分配的单元
进程隔离了正在执行的不同程序
优点:进程间相互独立互补影响
2.什么是线程? 进程中的一个执行单元(进程是程序的边界,要靠线程执行程序)线程执行方法 执行完毕释放线程是CPU分配时间片的单位 一个进程包含多个线程
且线程相互独立 共享当前进程的资源
3.操作系统的分类? 单任务和多任务
单任务操作系统: 单任务操作系统.png
2.多任务操作系统: 1.单核CPU多任务操作系统: 单核cpu多任务操作系统.png
4.如何创建一个线程? 第一种方式:创建Thread子类
java.lang.Thread 描述线程的类 我们想实现多线程 必须继承 Thread类
1.实现步骤: 1.创建一个Thread子类
2.重写run方法布置任务
3.创建Thread子类对象
4.调用Thread类中的Start方法 开启新线程 执行run方法
2.案例: ``` package MapList;
public class Thread1 extends Thread { //2.重写Thread类中的run方法 设置线程任务 public void run() { for(int i=0;i<20;i++) { System.out.println(“run:”+i); } }
}
package MapList;
public class MyThread { public static void main(String[]args) { Thread1 th=new Thread1(); th.start(); for(int i=0;i<20;i++) { System.out.println(“main”+i); }
} } 结果: main0 run:0 main1 main2 main3 main4 main5 run:1 main6 run:2 main7 run:3 main8 run:4 main9 main10 run:5 run:6 run:7 run:8 run:9 run:10 run:11 run:12 run:13 run:14 run:15 run:16 run:17 main11 main12 main13 main14 main15 main16 main17 main18 main19 run:18 run:19
```第二种方式:实现runnable接口
java. lang.Runable 接口应该由那些打算通过某一线程执行其实例的类实现
类必须定义一个 无参数的方法(方法用来布置任务)
Thread 类方法和构造方法
Thread(Runnabe target) 分配新的Thread对象
Thread(Runnable Target,String name)分配新的Thread对象
1.实现步骤: 1.创建一个Runnable接口实现类
2.在实现类中 重写Runnable接口的run方法
3.创建Runnable的实现类对象
4.创建Thread对象 构造方法中传递Runnable实现类对象
5.调用Thread的start方法
2.Runnable实现多线程的好处: 1.避免了单继承的局限性
2.增强了程序的拓展性,降低了耦合度(解耦)把继承关系变成组合关系
3.案例: package MapList;
public class RunnableImpl implements Runnable{
@Override public void run() { // TODO 自动生成的方法存根 for(int i=0;i<20;i++) { System.out.println("run:"+i); } } public static void main(String[]args) { Runnable r=new RunnableImpl(); Thread td=new Thread(r); td.start(); }} package MapList;
public class MyThread { public static void main01(String[]args) { Thread1 th=new Thread1();//继承 th.start(); run();
} private static void run() { for(int i=0;i<20;i++) { System.out.println("main"+i); } } public static void main(String[]args) { Runnable r=new RunnableImpl(); Thread td=new Thread(r); // 组合 任务与线程 td.start(); run(); }} 结果: main0 run:0 main1 main2 main3 main4 main5 run:1 main6 run:2 main7 run:3 main8 run:4 main9 main10 run:5 run:6 run:7 run:8 run:9 run:10 run:11 run:12 run:13 run:14 run:15 run:16 run:17 main11 main12 main13 main14 main15 main16 main17 main18 main19 run:18 run:19
4.匿名内部类实现多线程: ``` public static void main(String[]args) { Runnable runnable=new Runnable() {
@Override public void run() { // TODO 自动生成的方法存根 for(int i=0;i<20;i++) { System.out.println("runnable:"+i); } }}; new Thread(runnable).start(); new Thread(new Runnable() {//匿名内部类和匿名对象一块使用 public void run() { for(int i=0;i<20;i++) { System.out.println(“第三”+i); } } }).start(); Thread td= new Thread() { public void run() { for(int i=0;i<20;i++) { System.out.println(“run:”+i); } } }; td.start(); run(); }
} 结果: runnable:0 runnable:1 runnable:2 runnable:3 runnable:4 runnable:5 runnable:6 runnable:7 runnable:8 runnable:9 runnable:10 runnable:11 runnable:12 runnable:13 runnable:14 runnable:15 runnable:16 runnable:17 runnable:18 main0 main1 main2 main3 run:0 runnable:19 run:1 main4 main5 run:2 run:3 run:4 run:5 run:6 run:7 run:8 run:9 run:10 run:11 run:12 main6 run:13 run:14 run:15 run:16 run:17 run:18 run:19 第三0 main7 main8 第三1 第三2 第三3 第三4 第三5 main9 第三6 main10 main11 第三7 main12 第三8 main13 第三9 main14 第三10 main15 第三11 第三12 第三13 第三14 main16 第三15 main17 第三16 main18 main19 第三17 第三18 第三19
```5.Java如何决定执行那个线程 java是抢占式执行 可以设置线程的优先级(执行概率会大大提高)
6.多线程实现的原理 1.主线程执行原理 public class Demo1{
public static void main(String[]args){
System.out.println(“HelloWorld”)
}
}
分析:JVM执行main方法 main方法会进入栈内存,jvm会找操作系统开辟一条main方法通向cpu的执行路径,cup就可以通过这个执行路径来执行main方法,而这个路径取一个名字叫main(主)线程
主线程.png
2.多线程执行原理 多线程实现的原理2.png
3.内存上多线程实现的原理 多线程的内存示意图.png
7.线程冲突 1.线程中常用的方法 setName getName sleep currentThread
2.setName和getName案例 ``` package MapList; public class Thread1 extends Thread {
//2.重写Thread类中的run方法 设置线程任务 public void run() { setName(“线程1”); for(int i=0;i<20;i++) { System.out.println(getName()+i); } } } public static void main(String[]args) { Thread1 td=new Thread1(); //td.setName(“线程1”); td.start(); String name= td.getName();
System.out.println(name);} } 结果: Thread-0 线程10 线程11 线程12 线程13 线程14 线程15 线程16 线程17 线程18 线程19 线程110 线程111 线程112 线程113 线程114 线程115 线程116 线程117 线程118 线程119
```2.sleep方法的案例 ``` public static void main(String[]args) throws InterruptedException { // Thread1 td=new Thread1(); // td.setName(“线程1”); // td.start(); // String name= td.getName(); // // System.out.println(name); for(int i=0;i<20;i++) {
Thread.sleep(1000);//睡眠毫秒 System.out.println(i); }} } 结果: 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
```3.currentThread方法的案例 ``` public static void main(String[]args) throws InterruptedException { // Thread1 td=new Thread1(); // td.setName(“线程1”); // td.start(); // String name= td.getName(); // // System.out.println(name); for(int i=0;i<20;i++) { //Thread.sleep(1000); System.out.println(i); } System.out.println(Thread.currentThread()); 结果: Thread[main,5,main] System.out.println(Thread.currentThread().getName()); 结果: main System.out.println(Thread.currentThread().currentThread().currentThread()); //链式编程 结果: Thread[main,5,main]
} } 结果: 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
```4.线程冲突中买票的案例: ``` package MapList;
public class RunnableImpl1 implements Runnable{ //总票数 private int ticket=100; //设置线程任务买票 public void run() { while(true){ //使用无线循环让买票操作重复执行 if(ticket>0) { try { Thread.sleep(10);//模拟出票的过程
}catch(Exception e) { } System.out.println(Thread.currentThread().getName()+"正在买---->"+ticket+"张票"); ticket--; } }} } public static void main(String[]args) { Runnable r=new RunnableImpl1(); Thread td=new Thread®; td.start(); Thread td1=new Thread®; td1.start();
} } 结果: Thread-1正在买---->100张票 Thread-0正在买---->100张票 Thread-0正在买---->98张票 Thread-1正在买---->98张票 Thread-1正在买---->96张票 Thread-0正在买---->96张票 Thread-1正在买---->94张票 Thread-0正在买---->94张票 Thread-0正在买---->92张票 Thread-1正在买---->92张票 Thread-1正在买---->90张票 Thread-0正在买---->90张票 Thread-0正在买---->88张票 Thread-1正在买---->88张票 Thread-0正在买---->86张票 Thread-1正在买---->86张票 Thread-0正在买---->84张票 Thread-1正在买---->84张票 Thread-0正在买---->82张票 Thread-1正在买---->82张票 Thread-0正在买---->80张票 Thread-1正在买---->80张票 Thread-0正在买---->78张票 Thread-1正在买---->78张票 Thread-1正在买---->76张票 Thread-0正在买---->76张票 Thread-0正在买---->74张票 Thread-1正在买---->74张票 Thread-1正在买---->72张票 Thread-0正在买---->72张票 Thread-1正在买---->70张票 Thread-0正在买---->70张票 Thread-1正在买---->68张票 Thread-0正在买---->68张票 Thread-0正在买---->66张票 Thread-1正在买---->66张票 Thread-1正在买---->64张票 Thread-0正在买---->64张票 Thread-0正在买---->62张票 Thread-1正在买---->62张票 Thread-1正在买---->60张票 Thread-0正在买---->60张票 Thread-0正在买---->58张票 Thread-1正在买---->58张票 Thread-0正在买---->56张票 Thread-1正在买---->56张票 Thread-0正在买---->54张票 Thread-1正在买---->54张票 Thread-1正在买---->52张票 Thread-0正在买---->52张票 Thread-0正在买---->50张票 Thread-1正在买---->50张票 Thread-0正在买---->48张票 Thread-1正在买---->48张票 Thread-0正在买---->46张票 Thread-1正在买---->46张票 Thread-1正在买---->44张票 Thread-0正在买---->44张票 Thread-0正在买---->42张票 Thread-1正在买---->42张票 Thread-0正在买---->40张票 Thread-1正在买---->40张票 Thread-0正在买---->38张票 Thread-1正在买---->38张票 Thread-1正在买---->36张票 Thread-0正在买---->36张票 Thread-1正在买---->34张票 Thread-0正在买---->34张票 Thread-1正在买---->32张票 Thread-0正在买---->32张票 Thread-1正在买---->30张票 Thread-0正在买---->30张票 Thread-0正在买---->28张票 Thread-1正在买---->28张票 Thread-1正在买---->26张票 Thread-0正在买---->26张票 Thread-1正在买---->24张票 Thread-0正在买---->24张票 Thread-1正在买---->22张票 Thread-0正在买---->22张票 Thread-1正在买---->20张票 Thread-0正在买---->20张票 Thread-1正在买---->18张票 Thread-0正在买---->18张票 Thread-1正在买---->16张票 Thread-0正在买---->16张票 Thread-0正在买---->14张票 Thread-1正在买---->14张票 Thread-0正在买---->12张票 Thread-1正在买---->12张票 Thread-0正在买---->10张票 Thread-1正在买---->10张票 Thread-0正在买---->8张票 Thread-1正在买---->8张票 Thread-0正在买---->6张票 Thread-1正在买---->6张票 Thread-0正在买---->4张票 Thread-1正在买---->4张票 Thread-0正在买---->2张票 Thread-1正在买---->2张票 Thread-0正在买---->0张票 注意: 两个人同时去买票线程不安全 t0进来了线程抢到了cup的执行权 进入到run方法 执行到if之后 就失去了cpu执行权( 睡了) t1也进来了 (睡了)出现了一样的数据在减减之前同时执行到System.out.println()了。 (线程不安全)
```2.案例2 : public static void main(String[]args) { Runnable r=new RunnableImpl1(); Thread td=new Thread®; td.start(); Thread td1=new Thread®; td1.start(); Thread td2=new Thread®; td1.start(); } }
package MapList;
public class RunnableImpl1 implements Runnable{ //总票数 private int ticket=100; //设置线程任务买票 public void run() { while(true){ //使用无线循环让买票操作重复执行 if(ticket>0) { try { Thread.sleep(10);//模拟出票的过程
}catch(Exception e) { } System.out.println(Thread.currentThread().getName()+"正在买---->"+ticket+"张票"); ticket--; } } }} 结果: Thread-0正在买---->100张票 Thread-0正在买---->99张票 Thread-0正在买---->98张票 Thread-1正在买---->97张票 Thread-0正在买---->96张票 Thread-0正在买---->95张票 Thread-1正在买---->94张票 Thread-0正在买---->93张票 Thread-1正在买---->92张票 Thread-0正在买---->91张票 Thread-0正在买---->90张票 Thread-1正在买---->89张票 Thread-0正在买---->88张票 Thread-0正在买---->87张票 Thread-1正在买---->86张票 Thread-0正在买---->85张票 Thread-0正在买---->84张票 Thread-1正在买---->83张票 Thread-0正在买---->82张票 Thread-0正在买---->81张票 Thread-1正在买---->80张票 Thread-0正在买---->79张票 Thread-1正在买---->78张票 Thread-0正在买---->77张票 Thread-1正在买---->76张票 Thread-0正在买---->75张票 Thread-1正在买---->74张票 Thread-0正在买---->73张票 Thread-0正在买---->72张票 Thread-1正在买---->71张票 Thread-0正在买---->70张票 Thread-1正在买---->69张票 Thread-0正在买---->68张票 Thread-0正在买---->67张票 Thread-1正在买---->66张票 Thread-0正在买---->65张票 Thread-0正在买---->64张票 Thread-1正在买---->63张票 Thread-0正在买---->62张票 Thread-1正在买---->61张票 Thread-0正在买---->60张票 Thread-0正在买---->59张票 Thread-1正在买---->58张票 Thread-0正在买---->57张票 Thread-0正在买---->56张票 Thread-1正在买---->55张票 Thread-0正在买---->54张票 Thread-0正在买---->53张票 Thread-1正在买---->52张票 Thread-0正在买---->51张票 Thread-1正在买---->50张票 Thread-0正在买---->49张票 Thread-0正在买---->48张票 Thread-1正在买---->47张票 Thread-0正在买---->46张票 Thread-1正在买---->45张票 Thread-0正在买---->44张票 Thread-1正在买---->43张票 Thread-0正在买---->42张票 Thread-0正在买---->41张票 Thread-1正在买---->40张票 Thread-0正在买---->39张票 Thread-1正在买---->38张票 Thread-0正在买---->37张票 Thread-0正在买---->36张票 Thread-1正在买---->35张票 Thread-0正在买---->34张票 Thread-0正在买---->33张票 Thread-1正在买---->32张票 Thread-0正在买---->31张票 Thread-0正在买---->30张票 Thread-1正在买---->29张票 Thread-0正在买---->28张票 Thread-1正在买---->27张票 Thread-1正在买---->26张票 Thread-0正在买---->25张票 Thread-1正在买---->24张票 Thread-0正在买---->23张票 Thread-1正在买---->22张票 Thread-0正在买---->21张票 Thread-1正在买---->20张票 Thread-0正在买---->19张票 Thread-0正在买---->18张票 Thread-1正在买---->17张票 Thread-0正在买---->16张票 Thread-1正在买---->15张票 Thread-1正在买---->14张票 Thread-0正在买---->13张票 Thread-0正在买---->12张票 Thread-1正在买---->11张票 Thread-0正在买---->10张票 Thread-0正在买---->9张票 Thread-1正在买---->8张票 Thread-0正在买---->7张票 8.如何解决线程安全的问题 1.第一种方式 同步代码块 Synchronized(锁对象){
可能会出现线程安全的问题的代码
}
1.案例: ``` package MapList;
public class RunnableImpl1 implements Runnable{ //总票数 private int ticket=100; Object obj=new Object(); //设置线程任务买票 public void run() { while(true){ //使用无线循环让买票操作重复执行 //锁对象 任意 synchronized(obj) { if(ticket>0) { try { Thread.sleep(10);//模拟出票的过程
}catch(Exception e) { } System.out.println(Thread.currentThread().getName()+"正在买---->"+ticket+"张票"); ticket--; } } }} }
public static void main(String[]args) { Runnable r=new RunnableImpl1(); Thread td=new Thread®; td.start(); Thread td1=new Thread®; td1.start(); Thread td2=new Thread®; td1.start();
} }
结果: Thread-0正在买---->100张票 Thread-0正在买---->99张票 Thread-0正在买---->98张票 Thread-0正在买---->97张票 Thread-0正在买---->96张票 Thread-0正在买---->95张票 Thread-1正在买---->94张票 Thread-1正在买---->93张票 Thread-1正在买---->92张票 Thread-1正在买---->91张票 Thread-1正在买---->90张票 Thread-1正在买---->89张票 Thread-1正在买---->88张票 Thread-1正在买---->87张票 Thread-1正在买---->86张票 Thread-1正在买---->85张票 Thread-1正在买---->84张票 Thread-1正在买---->83张票 Thread-1正在买---->82张票 Thread-1正在买---->81张票 Thread-1正在买---->80张票 Thread-1正在买---->79张票 Thread-1正在买---->78张票 Thread-1正在买---->77张票 Thread-1正在买---->76张票 Thread-1正在买---->75张票 Thread-1正在买---->74张票 Thread-1正在买---->73张票 Thread-1正在买---->72张票 Thread-1正在买---->71张票 Thread-1正在买---->70张票 Thread-1正在买---->69张票 Thread-1正在买---->68张票 Thread-1正在买---->67张票 Thread-1正在买---->66张票 Thread-1正在买---->65张票 Thread-1正在买---->64张票 Thread-1正在买---->63张票 Thread-1正在买---->62张票 Thread-1正在买---->61张票 Thread-1正在买---->60张票 Thread-1正在买---->59张票 Thread-1正在买---->58张票 Thread-1正在买---->57张票 Thread-1正在买---->56张票 Thread-1正在买---->55张票 Thread-1正在买---->54张票 Thread-1正在买---->53张票 Thread-1正在买---->52张票 Thread-1正在买---->51张票 Thread-1正在买---->50张票 Thread-1正在买---->49张票 Thread-1正在买---->48张票 Thread-1正在买---->47张票 Thread-1正在买---->46张票 Thread-1正在买---->45张票 Thread-1正在买---->44张票 Thread-1正在买---->43张票 Thread-1正在买---->42张票 Thread-1正在买---->41张票 Thread-1正在买---->40张票 Thread-1正在买---->39张票 Thread-1正在买---->38张票 Thread-1正在买---->37张票 Thread-1正在买---->36张票 Thread-1正在买---->35张票 Thread-1正在买---->34张票 Thread-1正在买---->33张票 Thread-1正在买---->32张票 Thread-1正在买---->31张票 Thread-1正在买---->30张票 Thread-1正在买---->29张票 Thread-1正在买---->28张票 Thread-1正在买---->27张票 Thread-1正在买---->26张票 Thread-1正在买---->25张票 Thread-1正在买---->24张票 Thread-1正在买---->23张票 Thread-1正在买---->22张票 Thread-1正在买---->21张票 Thread-1正在买---->20张票 Thread-1正在买---->19张票 Thread-1正在买---->18张票 Thread-1正在买---->17张票 Thread-1正在买---->16张票 Thread-1正在买---->15张票 Thread-1正在买---->14张票 Thread-1正在买---->13张票 Thread-1正在买---->12张票 Thread-1正在买---->11张票 Thread-1正在买---->10张票 Thread-1正在买---->9张票 Thread-1正在买---->8张票 Thread-1正在买---->7张票 Thread-1正在买---->6张票 Thread-1正在买---->5张票 Thread-1正在买---->4张票 Thread-1正在买---->3张票 Thread-1正在买---->2张票 Thread-1正在买---->1张票
```注意事项:
1.通过代码块中的锁对象 可以使用任意的对象
2.但是必须保证多个线程使用的锁对象是一个
3.锁对象的作用:
把同步代码块锁住 只让一个线程在同步代码块执行
2.第二种 使用同步方法 步骤:1.把访问了共享数据的代码抽取出来放到一个方法中
2.把方法添加关键字synchronized
案例1: ``` package MapList;
public class RunnableImpl1 implements Runnable{ //总票数 private int ticket=10; Object obj=new Object(); //设置线程任务买票 public void run() { while(true){ //使用无线循环让买票操作重复执行 //锁对象 任意 //synchronized(obj) { extracted();
} //} } //锁的是thisprivate synchronized void extracted() { synchronized(this){ if(ticket>0) { try { Thread.sleep(10);//模拟出票的过程
}catch(Exception e) { } System.out.println(Thread.currentThread().getName()+"正在买---->"+ticket+"张票"); ticket--; }} } }
public static void main(String[]args) { Runnable r=new RunnableImpl1(); Thread td=new Thread®; td.start(); Thread td1=new Thread®; td1.start(); Thread td2=new Thread®; td1.start();
} }
```3.静态的同步方法 1.锁对象的问题: this是创建对象之后产生的 静态方法属于类优先于this所以静态没有this
2.静态方法的锁对象是本类class属性----->class文件对象(反射) 案例: ``` package MapList;
public class RunnableImpl1 implements Runnable{ //总票数 private static int ticket=10; Object obj=new Object(); //设置线程任务买票 public void run() { while(true){ //使用无线循环让买票操作重复执行 //锁对象 任意 //synchronized(obj) { extracted1();
} //} }private static synchronized void extracted1() { synchronized(RunnableImpl1.class){ if(ticket>0) { try { Thread.sleep(10);//模拟出票的过程
}catch(Exception e) { } System.out.println(Thread.currentThread().getName()+"正在买---->"+ticket+"张票"); ticket--; }} } }
public static void main(String[]args) { Runnable r=new RunnableImpl1(); Thread td=new Thread®; td.start(); Thread td1=new Thread®; td1.start(); Thread td2=new Thread®; td1.start();
} }
9.第三种方式 lock 1.java.util.concurrent.locks.lock
2.lock实现提供了比synchornized方法和语句可获得更广泛的锁定操作
3.lock接口中的方法:
1.void lock 获取锁
2.void unlock释放锁
4.使用步骤:
1.通过实现类创建接口对象ReentrantLock
2.在可能会出现安全问题的代码钱调用lock接口中的方法lock获取锁
3.在可能会出现安全问题的代码后调用lock接口中的方法unlock释放锁
案例:
```package MapList;
import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReentrantLock;
public class RunnableImpl1 implements Runnable{ //总票数 Lock l=new ReentrantLock(); private int ticket=10; Object obj=new Object(); //设置线程任务买票 public void run() {
while(true){ //使用无线循环让买票操作重复执行 //锁对象 任意 //synchronized(obj) { //extracted1();
//}
//} l.lock(); if(ticket>0) { try { Thread.sleep(10);//模拟出票的过程 }catch(Exception e) { } System.out.println(Thread.currentThread().getName()+"正在买---->"+ticket+"张票"); ticket--; } l.unlock(); }} private synchronized void extracted1() { synchronized(this) {
}} }
public static void main(String[]args) { Runnable r=new RunnableImpl1(); Thread td=new Thread®; td.start(); Thread td1=new Thread®; td1.start(); Thread td2=new Thread®; td1.start();
} }
结果: Thread-0正在买---->10张票 Thread-0正在买---->9张票 Thread-0正在买---->8张票 Thread-0正在买---->7张票 Thread-0正在买---->6张票 Thread-0正在买---->5张票 Thread-0正在买---->4张票 Thread-0正在买---->3张票 Thread-0正在买---->2张票 Thread-1正在买---->1张票
```案例2:
```package MapList;
import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReentrantLock;
public class RunnableImpl1 implements Runnable{ //总票数 Lock l=new ReentrantLock(); private int ticket=10; Object obj=new Object(); //设置线程任务买票 public void run() {
while(true){ //使用无线循环让买票操作重复执行 //锁对象 任意 //synchronized(obj) { //extracted1();
//}
//} l.lock(); if(ticket>0) { try { Thread.sleep(10);//模拟出票的过程 System.out.println(Thread.currentThread().getName()+"正在买---->"+ticket+"张票"); ticket--; }catch(Exception e) { } finally { l.unlock(); } } }} private synchronized void extracted1() { synchronized(this) {
}}
}
public static void main(String[]args) { Runnable r=new RunnableImpl1(); Thread td=new Thread®; td.start(); Thread td1=new Thread®; td1.start(); Thread td2=new Thread®; td1.start();
} }
结果: Thread-0正在买---->10张票 Thread-0正在买---->9张票 Thread-0正在买---->8张票 Thread-0正在买---->7张票 Thread-0正在买---->6张票 Thread-0正在买---->5张票 Thread-0正在买---->4张票 Thread-0正在买---->3张票 Thread-0正在买---->2张票 Thread-1正在买---->1张票
```10.线程的状态 线程状态.png
2.线程之间的通信 案例:
创建一个顾客线程(消费者) 告知老板要的包子的种类和数量 调用wait方法 放弃cpu执行 ,进入到waiting的状态
创建一个老板人线程(生产者) 花了5分钟做包子 做好包子之后 调用notify方法 唤醒顾客包子做好了。
注意:
顾客和老板线程必须使用同步代码块包裹起来 保证等待和唤醒只有一个在执行(包子是一个共享资源)同步使用的锁对象必须保证唯一
方法的调用: wait和notify 都是属于Object 的方法只有锁对象才能调用wait和notify
案例:
package TestDemo; /** strat之前 running运行状态 synchronized锁阻塞状态 排队 sleep秒表 wait()等待 @author lenovo * */ public class Test { static Object obj=new Object();//成员变量 对象唯一 public static void main(String[]args) { //消费者的线程 new Thread() { public void run() { while(true) { synchronized(obj){ System.out.println(“老板,来一个包子”); try { obj.wait(); }catch(InterruptedException e) { e.printStackTrace(); } System.out.println("顾客:包子已经做好了,开吃");// 被通知之后执行的 System.out.println("——————————"); } } } }.start(); //商家线程 new Thread() { public void run() { while(true) { try { Thread.sleep(5000); } catch (InterruptedException e) { // TODO 自动生成的 catch 块 e.printStackTrace(); }//花了五秒钟做包子 synchronized(obj) { System.out.println("老板:包子做好了,来取餐"); obj.notify(); //通知正在等待线程 } } }; }.start(); } } 结果: 老板,来一个包子 老板:包子做好了,来取餐 顾客:包子已经做好了,开吃 —————————— 老板,来一个包子 老板:包子做好了,来取餐 顾客:包子已经做好了,开吃案例2
package ThreadDemo2;
/**
strat之前running运行状态synchronized锁阻塞状态 排队sleep秒表wait()等待@author lenovo*/
public class Test { static Object obj=new Object();//成员变量 对象唯一 public static void main(String[]args) { //消费者的线程 new Thread() { public void run() { while(true) { synchronized(obj){ System.out.println(“老板,来一个包子”); try { obj.wait(); }catch(InterruptedException e) { e.printStackTrace();
} System.out.println("顾客1:包子已经做好了,开吃");// 被通知之后执行的 System.out.println("——————————"); } } } }.start(); new Thread() { public void run() { while(true) { synchronized(obj){ System.out.println("老板,来一个包子"); try { obj.wait(); }catch(InterruptedException e) { e.printStackTrace(); } System.out.println("顾客2:包子已经做好了,开吃");// 被通知之后执行的 System.out.println("——————————"); } } } }.start(); //商家线程 new Thread() { public void run() { while(true) { try { Thread.sleep(5000); } catch (InterruptedException e) { // TODO 自动生成的 catch 块 e.printStackTrace(); }//花了五秒钟做包子 synchronized(obj) { System.out.println("老板:包子做好了,来取餐"); // obj.notify(); obj.notifyAll(); //通知正在等待线程 } } }; }.start(); }}
结果: 老板,来一个包子 老板,来一个包子 老板:包子做好了,来取餐 顾客2:包子已经做好了,开吃 —————————— 老板,来一个包子 顾客1:包子已经做好了,开吃 —————————— 老板,来一个包子 老板:包子做好了,来取餐 顾客1:包子已经做好了,开吃 —————————— 老板,来一个包子 顾客2:包子已经做好了,开吃 3.等待唤醒机制 1. 点餐(进入等待)—>做餐(需要时间,通知顾客,等待)—>吃餐(需要 时间,吃完之后)—>点餐—>做餐
案例:
package TestDemo; public class Baozi { String pi; String xian; boolean flag=false; //包子的状态 //如果有 true 如果没有 false } package TestDemo; public class Baozipu extends Thread { private Baozi baozi; public Baozipu(Baozi zi) { this.baozi=zi; } public void run() {//生成 int count=0; //包子铺一直做包子 while(true) { synchronized(baozi) { if(baozi.flag==true) { //包子铺进入等待 try { baozi.wait();//等待 }catch(Exception e) { } } //如果没有包子 被唤醒之后执行的脚本 生产包子 if(count%2==0) { baozi.pi="白面皮"; baozi.xian="猪肉"; } else { baozi.pi="黑面皮"; baozi.xian="牛肉"; } count++; System.out.println("包子铺正在生产"+baozi.pi+baozi.xian); try { Thread.sleep(20); }catch(Exception e) { e.printStackTrace(); } //包子修改包子状态 baozi.flag=true; baozi.notify(); System.out.println("包子铺正在生产好了"+baozi.pi+baozi.xian); } } } } package TestDemo; public class Programmer extends Thread{ private Baozi bz; public Programmer(Baozi baozi) { this.bz=baozi; } public void run() { while(true){ synchronized(bz) { if(bz.flag==false) { try { bz.wait(); }catch(InterruptedException e) { e.printStackTrace(); } } //被唤醒之后执行的脚本 System.out.println("程序员正在吃:"+bz.pi+bz.xian); //吃完了 bz.flag=false; bz.notify();//通知商家接着做 System.out.println("程序员:"+bz.pi+bz.xian); System.out.println("------------------"); } } } } package TestDemo; public class Test { public static void main(String[]args) { Baozi b=new Baozi(); Baozipu bzp=new Baozipu(b); bzp.start(); Programmer pro=new Programmer(b); pro.start(); } }4.线程池 1.为什么要有线程池? 我们使用线程的时候 每次都是创建线程 频繁创建对象/线程 开销 性能消耗
2.线程池的示意图 3.线程池的好处 1.降低资源消耗 减少创建线程和销毁线程的次数 每个工作线程可以重复利用 可以执行多个任务
2.提高响应速度 当任务多的时候可以不用等待理解执行
3.提高线程的可管理性 可以根据系统的承受能力调整线程池的数量
4.线程是java1.5之后提供的 1.Java.util.concurrent.excutors 线程池的工厂类 用来生产线程池 2.Excutors类中的方法 1. static ExecutorService newFixedThreadPool(int nThreads)
创建一个可重用固定线程数的线程池,以共享的无界队列方式来运行这些线程。
2.返回值 ExecutorService接口 返回的是接口的实现类对象 接口接收这个对象
3.接口中的方法 1.submit 提交 提交一个任务 直接使用线程池中的线程 执行任务
2.shutdown 关闭线程
4.实现步骤: 1.使用线程池工厂类 创建对象
2.创建一个类 实现runnable接口 重写run方法 设置任务
3.调用ExecutorService中submit方法 传递线程任务 开启线程 执行run方法
4.调用ExecutorService 中shutdown方法 销毁线程(不建议执行)
案例:
```public static void main(String[] args) { //1 ExecutorService serv= Executors.newFixedThreadPool(3);//创建包含3个线程的线程池
//2-3.task 任务 serv.submit(new RunnableImp()); serv.submit(new RunnableImp()); serv.submit(new RunnableImp()); serv.submit(new RunnableImp()); serv.submit(new RunnableImp()); serv.submit(new RunnableImp()); serv.submit(new RunnableImp()); //3.销毁 serv.shutdown();
} }
package ThreadDemo2;
public class RunnableImp implements Runnable {
@Override public void run() { // TODO Auto-generated method stub try { Thread.sleep(1000); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } System.out.println(Thread.currentThread().getName()+“创建了一个新的线程执行”); } }
```11.lambda表达式 1.lambda表达式的含义: Java 8的一个大亮点是引入Lambda表达式,使用它设计的代码会更加简洁。当开发者在编写 Lambda表达式时,也会随之被编译成一个函数式接口。
2.下面这个例子就是使用Lambda语法来代替匿名的内部类,代码不仅简洁,而且还可读。 案例:
```第一种写法 package LambdaDemo;
public class RunnableImpl implements Runnable {
@Override public void run() { // TODO Auto-generated method stub System.out.println(“哈哈哈 美滋滋”); } public class Test {
public static void main1(String[] args) { //-------------第一种写法-------------------- RunnableImpl ru=new RunnableImpl(); Thread td=new Thread(ru); td.start(); } }
``` 案例2:
第二种写法 Runnable r=new Runnable() {
@Override public void run() { // TODO Auto-generated method stub System.out.println("美滋滋1"); } }; new Thread(r).start();} }
案例3:
第三种 new Thread(new Runnable() { @Override public void run() { System.out.println(“美滋滋2”); } }).start();
3.使用匿名内部类的问题 1.Thread类 需要runnable接口作为参数 其中的抽象run方法 是用来指定线程的任务的核心
2.为了指定run的方法体 不得不 需要runnable接口的实现类
3.为了省去定义一个runnable 实现了 不得不使用匿名内部类
4.必须覆盖重写 抽象方法run 所以方法名 返回值卡 参数列表 必须重写一遍 而且不能写错
5.而实际上 只有run方法的方法体才是我们关心的
6.lambda表达式替换匿名内部类
4.lambda表达式的格式 lambda表达式 ()->{}
分析:
a.一些参数 ()
b.一个箭头->
c.一段代码
格式说明:
(参数列表)->{一些重写方法的代码}
():接口中抽象方法的参数列表 没有参数 空着,有参数就写对应的参数 参数数量和顺序不能错
->传递的意思 把参数传递给方法体
{} 重写接口的抽象方法的方法体
案例:
public class Test { public static void main1(String[] args) { new Thread(()->{}).start();} ).start(); } } 案例:
```public class Test { public static void main02(String [] args){ //new Thread(()->{}); invokeCook(new Cook() {
@Override public void makeFood() { // TODO Auto-generated method stub System.out.println("梅菜扣肉"); } }); invokeCook(()->{System.out.println("鱼香肉丝");});//lambda表达式用来替换匿名内部类 //lambda表达式应用场景 一个有唯一抽象方法的接口// Cook cooker=new Cook() { // // @Override // public void makeFood() { // // TODO Auto-generated method stub // System.out.println(“北京烤鸭”); // } // }; // cooker.makeFood();
} //给定一个厨子 Cook接口 包含一个做饭的方法 方法无参数 没有返回值
//找厨子做饭 public static void invokeCook(Cook cooker){ cooker.makeFood();//接口指向实现类 多态 } }
}
package LambdaDemo;
public interface Cook {
void makeFood(); }
```5.函数式变成 (C#委托类型) 把一个方法 直接作为另外一个方法的参数
案例:
package LambdaDemo; public interface Sum { //int add(int a,int n); int add(int a); } public class Test { public static void main02(String [] args){ public static void main03(String[] args) { //(int b)->{return b+1;} // int number= // caculate((int b,int e)->{return b+e;},100,200); // // // int number1= // caculate((int b,int e)->b+e,100,200); // System.out.println(number); int number2= caculate(100,b->b+1); } public static int caculate(int a,Sum s){ return s.add(200); } public static void main(String[] args) { Student s1=new Student(10, "1"); Student s2=new Student(11, "1"); Student s3=new Student(12, "1"); Student [] arr=new Student[]{s1,s2,s3}; Arrays.sort(arr,new Comparator<Student>() { @Override public int compare(Student o1, Student o2) { // TODO Auto-generated method stub return o1.getAge()-o2.getAge(); } }); Arrays.sort(arr,(o1,o2)->o1.getAge()-o2.getAge()); } } package CollectionDemo; public class Student { int age; public int getAge() { return age; } public void setAge(int age) { this.age = age; } String name; public Student(int age, String name) { this.age = age; this.name = name; } @Override public int hashCode() { final int prime = 31; int result = 1; result = prime * result + age; result = prime * result + ((name == null) ? 0 : name.hashCode()); return result; } @Override public boolean equals(Object obj) { if (this == obj) return true; if (obj == null) return false; if (getClass() != obj.getClass()) return false; Student other = (Student) obj; if (age != other.age) return false; if (name == null) { if (other.name != null) return false; } else if (!name.equals(other.name)) return false; return true; } // @Override // public int hashCode() { // // TODO Auto-generated method stub // return 1; // } }