线程基本概念
1.什么是进程? -正在执行的程序
2.什么是线程? - 一个能够完成独立功能的执行路径,一个进程可有多个线程
3.为什么需要开启多线程?
- a. 当执行某些耗时操作的任务的时候需要开启多线程,防止线程阻塞
- b. 能够让两个任务看起来像是在同时执行
- c. 提高CPU的使用率,进而提高进程和内存的使用率(当键盘在输入的时候,main无法进行其他操作,一直等待输入操作完成,才执行之后的操作,内存使用率不高)
- 4.为什么开启多线程会同时执行? - 因为CPU切换执行的速度太快了,肉眼无法察觉
- 5.开启多线程是不是越多越好,提高了效率还是降低了效率? - 不是,线程越多,效率越慢,但是太少,浪费CPU资源,所以,合理利用CPU
- 6.并发和并行的区别
-
并发 --> 在同一个时间段下同时执行多个线程,看起来像同时执行
-
并行 --> 在同一个时间刻度下(不能够在分割的时间单位)执行多个线程,本质就上就是同时执行
注解:CPU在某一个最小的时间刻度单位下,执行的是一个进程的一个线程的一个不可再分割的原子性语句
举例: a++ 是线程安全的吗? 不是,声明a和a+1中间有不确定性(另一个进程也在调用a) a>0是安全的
7.同步和异步的区别 – 隐私文件
8.Java虚拟机的启动至少开启了两条线程,主线程和垃圾回收线程
实际操作
Thread简介:
Thread是个普通类
Thread实现了Runnable接口重写了run方法
启动线程的两种方式:
Thread启动线程:
新建class类A继承Thread类,重写run方法:(方法体中可以写方法调用/普通代码)
在测试类的main方法中new A 生成a对象调用start方法,而不是run
Runnable接口启动:
新建类B实现接口Runnable,重写run方法:(方法体中可以写方法调用/普通代码)
在测试类的main方法中th=new Thread(b):将B类的对象b作为参数传入
th调用start方法
案例:要求123功能同时进行:
两种方式实现:
1遍历文件所有
2拷贝文件输出在控制台
3主方法打印1-1000
测试类:
public static void main(String[] args) {
// TODO Auto-generated method stub
Searchfile sf = new Searchfile(new File("src"));
sf.start();
CopyfileImp cf = new CopyfileImp(new File("a.txt"),new File("acopy2.txt"));
Thread t=new Thread(cf);
t.start();
for(int i=0;i<1000;i++)
System.out.println(i+"main++++++++++");
}
遍历文件夹下所有文件目录
class Searchfile extends Thread{
File file;
public Searchfile(File file) {
super();
this.file = file;
}
public void sreach(File files){
if(files==null)
throw new NullPointerException();
File[] fs = files.listFiles();
if(fs.length!=0&&fs!=null)
for (File f : fs) {
if(f.isDirectory()){
sreach(f);
}else{
System.out.println(f.getName());
//if(f.isFile()&&f.getName().endsWith(""))
}
}
System.out.println(files.getName());
}
@Override
public void run() {
// TODO Auto-generated method stub
super.run();
sreach(file);
}
}
拷贝文件输出在控制台
class CopyfileImp implements Runnable{
File srcfile;
File descfile;
public CopyfileImp(File srcfile, File descfile) {
super();
this.srcfile = srcfile;
this.descfile = descfile;
}
@Override
public void run() {
// TODO Auto-generated method stub
copy();
}
public void copy(){
try(BufferedOutputStream bo = new BufferedOutputStream(new FileOutputStream(descfile,true));
BufferedInputStream bi = new BufferedInputStream(new FileInputStream(srcfile));
){
int len=0;
byte[] bs=new byte[124];
while((len=bi.read(bs))!=-1){
bo.write(bs);
bo.flush();
}
} catch (FileNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
}
}
实现线程实例化的几种方法:
尤其注意第四种:继承Thread和实现Runnable接口都有时,只会调用Thread中的run方法
1//匿名子类对象
new Thread(){};
2//匿名子类对象
new Thread(){
@Override
public void run() {
// TODO Auto-generated method stub
for(int i=0;i<100;i++)
System.out.println(i);
}
}.start();
3//匿名对象,参数为接口实现类的匿名对象
new Thread(new Runnable(){
@Override
public void run() {
// TODO Auto-generated method stub
for(int i=0;i<100;i++)
System.out.println(" + + "+i);
}
}).start();;
4//匿名子类对象,参数为接口实现类的匿名对象
//注意:继承Thread和实现Runnable接口都有时,只会调用Thread中的run方法
//只打印System.out.println("thread + + "+i);
new Thread(new Runnable(){
public void run() {
// TODO Auto-generated method stub
for(int i=0;i<100;i++)
System.out.println("jiekou + + "+i);
}
}
){
public void run() {
// TODO Auto-generated method stub
for(int i=0;i<100;i++)
System.out.println("thread + + "+i);
}
}.start();;
Lambda表达式开启线程
什么是Lambda表达式 一种函数式接口的新的写法,本质还是匿名内部类,但是这个父类是函数式接口
什么是函数式接口?
– 只有一个抽象方法的接口称为函数式接口(到时调用的时候就可以不用写方法名称,很方便!)
Runnable, FileFilter
Lambda表达式的语法:
-
() -> {}
-
() 小括号里面是参数列表,如果一个函数式接口中的抽象方法没有参数,这里可以不写参数
-
-> 固定格式
-
{} 重写函数式接口的抽象方法的方法体
-
如果方法体中只有一条语句,{} 可以省略不写,如果返回值只有一条语句, return关键字要省略
接口如下:
@FunctionalInterface
interface ITest {
void show();
}
@FunctionalInterface
interface IDemo {
void show(int a, String b);
}
@FunctionalInterface
interface IShow {
int add(int a, int b);
}
普通类,和三个接口具有关联关系
class Demo {
public void method(ITest test) {
test.show(); //调用抽象方法
}
public void method(IDemo d) {
d.show(10, "sss");
}
public void method(IShow s) {
int add = s.add(100, 200);
System.out.println(add);
}
}
具体实现:
public class ThreadDemo05 {
public static void main(String[] args) {
new Demo().method(()->System.out.println("Lambda表达式的 show"));
//进method的接口,接口中的方法没有参数:ITest -》void show();
new Demo().method((a, b)->System.out.println(a + "|" + b));
//进method的接口,接口中的方法有两个参数,没有返回值: IDemo -》void show(int a, String b);
new Demo().method((a, b)->a + b);
//进method的接口,接口中的方法有两个参数,有返回值:IShow -》int add(int a, int b);
}
引出大头:
//因为这是构造方法实现子类匿名对象,其中参数是Runnable接口的实现类
刚好他的实现类可以用lambda表达式进行:run方法没有参数所以空() 再{ }写入方法体即可!
new Thread(()->{
System.out.println("Lambda表达式开启线程");
for (int i = 0; i < 10000; i++) {
System.out.println("Lambda:" + i);
}
}).start();