1、线程和进程的区别
进程:是指一个内存中运行的应用程序(已经在内存中运行的程序). 一个进程都有一个独立的内存空间,一个电脑(手机)可以同时运行多个进程;进程也是程序的一次执行过程,是系统运行程序的基本单位;
线程:是进程中的一个执行单元(线程是依赖于进程的),负责当前进程中程序的执行,一个进程中至少有一个线程(单线程程序)。一个进程中是可以有多个线程的,这个应用程序也可以称之为多线程程序。
并发和并行
前提
多个任务
多个线程
是线程的特性
高性能、高可用、高并发(三高)
并行:指两个或多个事件在同一时刻发生(同时发生 同时处理 执行者不是一个)。
并发:指两个或多个事件在同一个时间段内发生(交替的发生 执行者是一个)。
电脑在执行任务的时候是采用并发还是并行?
使用的是并发, 因为电脑上只有一个CPU,但是电脑上好像却可以同时运行多个程序,同时开了多个线程,其实这是一种假象,因为CPU的计算速度极快,约每秒50亿次计算,而人能感觉到的时间流失是秒,所以电脑给我们一种感觉好像电脑上程序在同时执行.
计算机CPU都是-Java抢占式调度。 每一个线程都会执行到,但是不一定时按序执行,执行取决于线程优先级,CPU有自己算法。
2 线程创建三种基本方式
2.1 继承Thread类
1、Thread就是一个线程类,里面定义所有和线程相关的功能,只有是这个类才能开启线程,才能被CPU单独去执行.Java中线程执行的时候是采用的并发(因为是让CPU执行JAVA中线程里封装的任务). 学习的过程中不要纠结于多个线程执行的结果,因为是随机在执行,抢占式的在使用CPU资源(抢占式任务调度)。
2、java虚拟机采用抢占式调度模型,是指优先让可运行池中优先级高的线程占用CPU(不绝对),如果可运行池中的线程优先级相同,那么就随机选择一个线程,使其占用CPU。
3、实现步骤
1、定义一个类MyThread继承Thread类 在MyThread类中重写run()方法,添加自己的任务
2、创建MyThread类的对象
3、启动线程 .start()
注意事项:千万不要使用线程对象调用run方法,因为并没有开启线程
观察结果:验证是否是抢占式调度。
public class ThreadExample extends Thread{//重写run@Overridepublic void run() {for (int i = 0; i < 200; i++){System.out.println("extends Thread run = " + i);}}
}
public class App {public static void main(String[] args) {ThreadExample te1 = new ThreadExample();ThreadExample te2 = new ThreadExample();//te.run();//调用run方法就没有开启线程,仅仅是使用线程对象调用了方法而已te1.start();te2.start();//main线程for (int i = 0; i < 100; i++){System.out.println("main Thread = " + i);}}
}
2.2 实现Runnable接口
1、@FunctionalInterface
public interface Runnable {
public abstract void run();
}
//这是一个函数式接口,规定里面只有一个run方法那么只需要让一个类实现Runnable接口即可,并且也需要覆写run方法。
2、Thread的构造方法创建对象的时候传入了Runnable接口的对象 Runnable接口对象重写run方法相当于指定线程任务,创建线程的时候绑定了该线程对象要做的任务
Runnable的对象称之为:线程任务对象 不是线程对象必须要交给Thread线程对象通过Thread的构造方法, 就可以把任务对象Runnable,绑定到Thread对象中, 将来执行start方法,就会自动执行。
3、实现步骤
1.定义一个类MyRunnable实现Runnable接口
2.在MyRunnable类中重写run()方法
3.创建MyRunnable类的对象
4.创建Thread类的对象,把MyRunnable对象作为构造方法的参数(绑定任务到线程对象)
5.启动线程
public class RunnableExample implements Runnable{@Overridepublic void run() {System.out.println("implements Runnable run()");}
}
public class App {public static void main(String[] args) {//线程任务类RunnableExample re = new RunnableExample();//定义线程对象Thread thread = new Thread(re);//一个线程任务可以绑定多个线程Thread thread2 = new Thread(re);//开启线程thread.start();thread2.start();for (int i = 0; i < 1000; i++) { System.out.println("我是主线程中任务....");}
}
}
2.3 实现Callable接口
1、@FunctionalInterface
public interface Callable {
V call() throws Exception;
}
2、
3、实现步骤
1.在MyCallable类中重写call()方法 这就是线程任务方法.这个方法有返回值.
创建MyCallable类的对象
2.创建FutureTask的实现类FutureTask对象,把MyCallable对象作为构造方法的参数
3.创建Thread类的对象,把FutureTask对象作为构造方法的参数
4.启动线程
5.再调用get方法,就可以获取线程结束之后的结果。 call方法什么时候执行完,get才会执行.就可以拿到任务执行完后结果.
public class CallableExample implements Callable {
@Overridepublic String call() throws Exception {for (int i = 0; i < 10; i++) {System.out.println(i+"-"+Thread.currentThread().getName(
));
}return "哈哈,我是返回值";
}public static void main(String[] args) throws ExecutionException
, InterruptedException {//线程任务CallableExample ce = new CallableExample();//线程任务类 - 只有这个FutureTask能接受返回值FutureTask ft = new FutureTask(ce);FutureTask ft1 = new FutureTask(ce);//线程类Thread t = new Thread(ft); //构造函数中只能传Runnable或Runnabl
e的实现类t.start();Thread t1 = new Thread(ft1); //构造函数中只能传Runnable或Runna
ble的实现类t1.start();System.out.println("t线程:"+ft.get()); //这是返回值System.out.println("t1线程:"+ft1.get()); //这是返回值
}
}
2.4 三种实现多线程方式总结
1、Thread 继承就不能继承其他类了,适合于这个任务只想被一个线程的对象执行的情况。
2、Runnable 解决单继承的问题(多实现),适合于一个任务想被多个线程执行的情况。
3、Callable 解决单继承的问题(多实现),适合于一个任务想被多个线程执行的情况,同时又返回结果,也可以抛异常。同时FutureTask可以判断线程是否执行完毕或取消执行。
3 线程Thread类
3.1 线程名称

默认主线程操作名字
public class GetThreadName {public static void main(String[] args) {//主线程for (int i = 0; i < 10; i++) {System.out.println("i = " + i + Thread.currentThread().getName());
}//获取当前线程对象Thread t = Thread.currentThread();System.out.println("t.getName() = " + t.getName());t.setName("主线程");System.out.println("t.getName() = " + t.getName());
}
Runnable接口子线程-1
public class RunnableName {public static void main(String[] args) {Runnable r = ()->{System.out.println("我是子线程" + Thread.currentThread().getName());
};Thread t = new Thread(r);//重新设置名称t.setName("Runnable子线程");System.out.println("t.getName() = " + t.getName());t.start();}
}
Runnable接口子线程-通过构造方法
public static void main(String[] args) {Thread t = new Thread(() ->{System.out.println(Thread.currentThread().getName());},"子线程");System.out.println("t.getName() = " + t.getName());t.start();
}
3.2 线程休眠
1、static void sleep(long millis) throws InterupterException
是一个静态方法,而且方法上还有编译时异常的声明,使用时一定要处理异常. 使当前正在执行的线程停留(暂停执行)指定的毫秒数, 1s = 1000ms, 过了指定的时间还会醒,可以继续执行任务
主线程休眠
public class MainSleep {public static void main(String[] args) throws InterruptedExcepti
on {for (int i = 0; i <10 ; i++) {Thread.sleep(1000);System.out.println("=========="+ i);}}
}
子线程休眠
public class ChildSleep {public static void main(String[] args) {Thread t = new Thread(()->{for (int i = 0; i < 10; i++) {try {Thread.sleep(1000);//TimeUnit.SECONDS.sleep(1); 工具类System.out.println("================"+ i);} catch (InterruptedException e) {e.printStackTrace();}}});t.start();}
}













