java.thread
任务:
同一时间只能做一件事
由上图可知:
调用 run();方法并不会开启新线程;
调用 start();方法会开启新线程。
程序:是指令和数据的有序集合,其本身没有任何运行的含义,是一个静态的概念。
进程(process):实质性程序的一次执行过程,它是一个动态的概念。是系统资源分配的单位;
进程和线程的关系:通常再一个进程中可以包含若干个线程,一个进程至少有一个线程,不然没有存在的意义。
线程(thread):是CPU调度和执行的单位
注意:很多 多线程是模拟出来的,真正的多线程是指有多个cpu,即多核,如服务器。如果是模拟出来的多线程,即在一个cpu的情况下,在同一个时间点,cpu只能执行一个代码,因为其切换的很快,所以就有同时执行的错觉。
核心概念: - 县城就是独立的执行路径; - 在程序执行时,即使没有自己创建线程,后台也会有多个线程,比如:主线程,GC线程; - main() 称之为主线程,是系统的入口,用于执行整个程序; - 在一个进程中,如果开辟了多个线程,线程的运行由调度器安排调度,调度器是与操作系统紧密想关的,先后顺序是不能人为干预的; - 对同一份资源操作时,会存在资源抢夺的问题,需要加入并发控制; - 线程会带来额外的开销,比如cpu调度时间,并发控制开销。 - 每个线程在自己的工作内存交互,内存控制不当会造成数据不一致。2.线程的创建(重点)
实现现成的三种方式:
2.1. 继承Thread类,创建线程(重点)继承 Thread类(重点),底层继承 runnable
实现 Runnable接口(*重点)
实现 Callable接口(现阶段—了解)
public class Thread
Thread extends Object
implements Runnable
线程是程序中执行的线程。 Java虚拟机允许应用程序同时执行多个执行线程。
每个线程都有优先权。 具有较高优先级的线程优先于优先级较低的线程执行。
创建一个新的执行线程有两种方法。
方法1:是将一个类声明为Thread的子类。 这个子类应该重写run类的方法Thread 。 然后可以分配并启动子类的实例。 例如,计算大于规定值的素数的线程可以写成如下:
public class TestThread_1 extends Thread{
//重写 run();方法,方法线程体
@Override
public void run() {
for (int i = 0; i < 20; i++) {
System.out.println("看代码---"+ i);
}
}
//main方法,主线程
public static void main(String[] args) {
//创建一个线程对象
TestThread_1 testThread1 = new TestThread_1();
//调用start()方法开启线程
testThread1.start();
for (int i = 0; i < 200; i++) {
System.out.println("-------学习多线程----"+ i);
}
}
}
!!注意:线程不一定立即执行,CPU安排调度,(每次执行会有区别)
2.2. 实现Runnable接口,创建线程(重点)方法2:是创建一个线程是声明实现类Runnable接口。 那个类然后实现了run方法。 然后可以分配类的实例,在创建Thread时作为参数传递,并启动。 这种其他风格的同一个例子如下所示:
public class TestThread_3 implements Runnable{
//重写 run();方法, 方法线程体
@Override
public void run() {
for (int i = 0; i < 20; i++) {
System.out.println("看代码---"+ i);
}
}
//main方法,主线程
public static void main(String[] args) {
//创建 runnable接口的实现类
TestThread_3 testThread_3 = new TestThread_3();
//创建线程对象,通过线程对象来开启我们的线程,(这是个代理)
new Thread(testThread_3).start();
for (int i = 0; i < 200; i++) {
System.out.println("-------学习多线程----"+ i);
}
}
}
每个线程都有一个用于识别目的的名称。 多个线程可能具有相同的名称。 如果在创建线程时未指定名称,则会为其生成一个新名称。
除非另有说明,否则将null参数传递给null中的构造函数或方法将导致抛出NullPointerException 。
继承 Thread类: - 子类继承 thread类, 子类具备多线程能力 - 启动线程:子类对象.start(); - 不建议使用:避免OOP单继承局限性 实现 Runnable接口: - 实现 Runnable接口,具有多线程能力 - 启动线程:传入目标对象+ Thread对象.start(); - 推荐使用:避免单继承局限性,灵活方便,方便同一个对象被多个线程使用 //一份资源 StartThread4 startThread = new StartThread4(); //多个代理 new Thread(station,"jack").start(); new Thread(station,"tom").start(); new Thread(station,"jerry").start();
案例3:
public class TestThread5 implements Runnable{
// 票数
private int ticketNums = 10;
@Override
public void run() {
while (true) {
if (ticketNums <= 0) {
break;
}
// 模拟延时
try {
Thread.sleep(200);
} catch (InterruptedException e) {
e.printStackTrace();
}
//Thread.currentThread().getName()获取线程名称
System.out.println(Thread.currentThread().getName() +"-->拿到了第"+ ticketNums--);
}
}
public static void main(String[] args) {
TestThread5 testThread5 = new TestThread5();
new Thread(testThread5,"小明").start();
new Thread(testThread5,"小红").start();
new Thread(testThread5,"黄牛").start();
}
}
2.3. 实现Callable接口,创建线程(了解)
步骤:
- 实现Callable接口,需要返回值类型
- 重写 call方法,需要抛出异常
- 创建目标对象
- 创建执行服务:ExecutorService ser = Executors.newFixedThreadPool(1);
- 提交执行:Future< Boolean > result1 = ser.submit(t1);
- 获取结果:boolean r1 = result1.get();
- 关闭服务:ser.shutdownNow();
public class TestThread_7Callable implements Callable {
//网络图片地址
private String url;
//保存的文件名字
private String fileName;
public TestThread_7Callable(String url, String fileName) {
this.url = url;
this.fileName = fileName;
}
//重写 call();方法,图片下载执行体
@Override
public Boolean call() throws Exception {
WebDownloader3 webDownloader = new WebDownloader3();
webDownloader.downloader(url, fileName);
System.out.println("下载的文件名:" + fileName);
return true;
}
public static void main(String[] args) throws ExecutionException, InterruptedException {
TestThread_7Callable t1 = new TestThread_7Callable("https://t7.baidu.com/it/u=1595072465,3644073269&fm=193&f=GIF", "7.jpg");
TestThread_7Callable t2 = new TestThread_7Callable("https://t7.baidu.com/it/u=1595072465,3644073269&fm=193&f=GIF", "8.jpg");
TestThread_7Callable t3 = new TestThread_7Callable("https://t7.baidu.com/it/u=1595072465,3644073269&fm=193&f=GIF", "9.jpg");
// 4.创建执行服务
ExecutorService ser = Executors.newFixedThreadPool(3);
// 5.提交执行
Future result1 = ser.submit(t1);
Future result2 = ser.submit(t2);
Future result3 = ser.submit(t3);
// 6.获取结果,(call方法返回的结果)
boolean r1 = result1.get();
boolean r2 = result2.get();
boolean r3 = result3.get();
// 7.关闭服务
ser.shutdownNow();
}
}
class WebDownloader3 {
//下载方法
public void downloader(String url, String fileName) {
try {
FileUtils.copyURLToFile(new URL(url), new File(fileName));
} catch (IOException e) {
e.printStackTrace();
System.out.println("IO异常,download方法出现问题");
}
}
}



