多线程
线程简介
任务,进程,线程,多线程
多任务:在现实生活中同时做多件事,看起来是多个任务都在做,实际上我们的大脑在同一时间只做了一件事情
线程:线程,有时被称为轻量级进程(Lightweight Process,LWP),是程序执行流的最小单元。一个标准的线程由线程ID,当前指令指针(PC),寄存器集合和堆栈组成。另外,线程是进程中的一个实体,是被系统独立调度和分派的基本单位,线程自己不拥有系统资源,只拥有一点儿在运行中必不可少的资源,但它可与同属一个进程的其它线程共享进程所拥有的全部资源。一个线程可以创建和撤消另一个线程,同一进程中的多个线程之间可以并发执行。由于线程之间的相互制约,致使线程在运行中呈现出间断性。每一个程序都至少有一个线程,若程序只有一个线程,那就是程序本身。
线程是程序中一个单一的顺序控制流程。在单个程序中同时运行多个线程完成不同的工作,称为多线程。
在Java Web中要注意,线程是JVM级别的,在不停止的情况下,跟JVM共同消亡,就是说如果一个Web服务启动了多个Web应用,某个Web应用启动了某个线 程,如果关闭这个Web应用,线程并不会关闭,因为JVM还在运行,所以别忘了设置Web应用关闭时停止线程。
进程:一个进程可以有多个线程,如视频中的声音,图像,字幕等。进程是操作系统结构的基础;是一次程序的执行;是一个程序及其数据在处理机上顺序执行时所发生的活动。操作系统中,几乎所有运行中的任务对应一条进程(Process)。一个程序进入内存运行,即变成一个进程。进程是处于运行过程中的程序,并且具有一定独立功能。描述进程的有一句话非常经典——进程是系统进行资源分配和调度的一个独立单位。
进程是系统中独立存在的实体,拥有自己独立的资源,拥有自己私有的地址空间**。**进程的实质,就是程序在多道程序系统中的一次执行过程,它是动态产生,动态消亡的,具有自己的生命周期和各种不同的状态。进程具有并发性,它可以同其他进程一起并发执行,按各自独立的、不可预知的速度向前推进。
(注意,并发性(concurrency)和并行性(parallel)是不同的。并行指的是同一时刻,多个指令在多台处理器上同时运行。并发指的是同一时刻只能有一条指令执行,但多个进程指令被被快速轮换执行,看起来就好像多个指令同时执行一样。)
进程由程序、数据和进程控制块三部分组成。
普通方法调用和多线程
Process与Thread
- 说起进程,就不得不说下程序。程序是指令和数据的有序集合,其本身没有任何运行的含义,是一个静态的概念。
- 而进程则是执行程序的一次执行过程,它是一个动态的概念。是系统资源分配的单位
- 通常在一个进程中可以包含若干个线程,当然一个进程中至少有一个线程,不然没有存在的意义。线程是CPU调度和执行的的单位。
注意:很多多线程是模拟出来的,真正的多线程是指有多个cpu,即多核,如服务器。如果是模拟出来的多线程,即在一个cpu的情况下,在同一个时间点,cpu只能执行一个代码,因为切换的很快,所以就有同时执行的错局。
线程的创建和启动
- Thread class,继承Thread类
- Runnable接口,实现Runnable接口
- Callable接口,实现Callable接口
1、继承Thread类创建线程类
通过继承Thread类创建线程类的具体步骤和具体代码如下:
• 定义一个继承Thread类的子类,并重写该类的run()方法;
• 创建Thread子类的实例,即创建了线程对象;
• 调用该线程对象的start()方法启动线程。
class SomeThead extends Thraad {
public void run() {
//do something here
}
}
public static void main(String[] args){
SomeThread oneThread = new SomeThread();
//步骤3:启动线程:
oneThread.start();
}
案列:下载网图
public class TestThread extends Thread {
//
private String url;
private String name;
public TestThread(String url,String name){
this.url = url;
this.name = name;
}
@Override
public void run() {
//下载图片
WebDownloader webDownloader = new WebDownloader();//下载器
webDownloader.downloader(url,name);//下载文件的方式
System.out.println("下载了图片-->"+name);
}
public static void main(String[] args) {
TestThread t1 = new TestThread("","1.jpg");
TestThread t2 = new TestThread("","2.jpg");
TestThread t3 = new TestThread("","3.jpg");
t1.start();
System.out.println("执行了t1");
t2.start();
System.out.println("执行了t2");
t3.start();
System.out.println("执行了t3");
}
}
//下载图片
class WebDownloader{
//下载方法
public void downloader(String url,String name){
try {
FileUtils.copyURLToFile(new URL (url),new File (name));
} catch (IOException e) {
e.printStackTrace();
//输出异常信息
System.out.println("downloader方法出现异常");
}
}
}
2、实现Runnable接口创建线程类
通过实现Runnable接口创建线程类的具体步骤和具体代码如下:
• 定义Runnable接口的实现类,并重写该接口的run()方法;
• 创建Runnable实现类的实例,并以此实例作为Thread的target对象,即该Thread对象才是真正的线程对象。
class SomeRunnable implements Runnable {
public void run() {
//do something here
}
}
Runnable oneRunnable = new SomeRunnable();
Thread oneThread = new Thread(oneRunnable);
oneThread.start();
案列:龟兔赛跑
public class Race implements Runnable{
//winner:只有一个胜利者
private static String winner;
@Override
public void run() {
//赛道
for (int step = 1; step <= 101; step++) {
//兔子休眠
if (Thread.currentThread().getName().equals("兔子") && step % 50==0){
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
//判断比赛是否结束
boolean flag = gameOver(step);
if (flag){
break;
}
System.out.println(Thread.currentThread().getName()+"跑了"+ step +"步");
}
}
//判断比赛是否结束
private boolean gameOver(int step){
if (winner!=null){ //如果存在胜利者
return true;
}
if (step>=100){ //如果跑到了比赛结束
winner = Thread.currentThread().getName();
System.out.println("比赛结束");
System.out.println("胜利者----->"+winner);
return true;
}
return false;
}
public static void main(String[] args) {
Race race = new Race();
new Thread(race,"兔子").start();
new Thread(race,"乌龟").start();
}
}
3、通过Callable和Future创建线程
通过Callable和Future创建线程的具体步骤和具体代码如下:
• 创建Callable接口的实现类,并实现call()方法,该call()方法将作为线程执行体,并且有返回值。
• 创建Callable实现类的实例,使用FutureTask类来包装Callable对象,该FutureTask对象封装了该Callable对象的call()方法的返回值。
• 使用FutureTask对象作为Thread对象的target创建并启动新线程。
• 调用FutureTask对象的get()方法来获得子线程执行结束后的返回值其中,Callable接口(也只有一个方法)定义如下:
public interface Callable {
V call() throws Exception;
}
步骤1:创建实现Callable接口的类SomeCallable;
步骤2:创建一个类对象:
Callable oneCallable = new SomeCallable();
步骤3:由Callable创建一个FutureTask对象:
FutureTask oneTask = new FutureTask(oneCallable);
注释: FutureTask是一个包装器,它通过接受Callable来创建,它同时实现了 Future和Runnable接口。
步骤4:由FutureTask创建一个Thread对象:
Thread oneThread = new Thread(oneTask);
步骤5:启动线程:
oneThread.start();
静态代理
把不想做的,琐碎的事找个代理做
public class StaticProxy {
public static void main(String[] args) {
//代理对象 代理 真实对象
You you = new You();
you.happyMarry();
new WeddingCompany(you).happyMarry();
}
}
//真实对象:你
class You implements Marry{
@Override
public void happyMarry() {
System.out.println("我要结婚了,好hi呦");
}
}
//代理对象:婚庆公司
class WeddingCompany implements Marry{
//婚庆需要有你这个人 , 代理对象需要代理一个真实对象
private Marry you;
public WeddingCompany(Marry you){
this.you = you;
}
@Override
public void happyMarry() {
before();
this.you.happyMarry();//你要结婚
after();
}
private void before() {
System.out.println("结婚之前,布置洞房");
}
private void after() {
System.out.println("结婚之后,催你收钱");
}
}
//共同的接口:结婚
interface Marry{
void happyMarry();
}
Lamda表达式
- λ希腊字母表中排序第十一位的字母,英语名称为Lambda
- 避免匿名内部类定义过多
- 其实质属于函数式编程的概念
public class Test03 {
public static void main(String[] args) {
ILove love = new Love();
love.lambda(1);
//匿名内部类
love = new ILove() {
@Override
public void lambda(int a) {
System.out.println("我开始喜欢lambda了...."+a);
}
};
love.lambda(2);
//lambda表达式
love = (int a)->{
System.out.println("我开始喜欢lambda了...."+a);
};
love.lambda(3);
//简化1: 去掉括号
love = a->{
System.out.println("我开始喜欢lambda了...."+a);
};
love.lambda(4);
//简化2:去掉花括号
love = a->System.out.println("我开始喜欢lambda了...."+a);
love.lambda(5);
}
}
//函数式接口
interface ILove{
void lambda(int a);
}
class Love implements ILove{
@Override
public void lambda(int a) {
System.out.println("我开始喜欢lambda了...."+a);
}
}