程序 (program)
是为完成特定任务、用某种语言编写的一组指令的集合。程序 - 数据结构 + 算法,主要指存放在硬盘上的可执行文件。
进程(process)
是 主要指运行在内存中的可执行文件。。是一个动态的过程:有它自身的产生、存在和消亡的过程。——生命周期(如:运行中的QQ,运行中的MP3播放器)
一个进程包括由操作系统分配的内存空间,包含一个或多个线程。
进程作为资源分配的单位,系统在运行时会为每个进程分配不同的内存区域
线程就是进程内部的程序流,也就是说操作系统内部支持多进程的,而每个进程的内部又是支持多线程的,线程是轻量的,新建线程会共享所在进程的系统资源,因此目前主流的开发都是采用多线程。
线程作为调度和执行的单位,每个线程拥有独立的运行栈和程序计数器(pc),线程切换的开销小,但是线程不能独立的存在,它必须是进程的一部分。一个进程一直运行,直到所有的非守护线程都结束运行后才能结束
一个进程中的多个线程共享相同的内存单元/内存地址空间,
多个线程从同一堆中分配对象,可以访问相同的变量和对象。这就使得线程间通信更简便、高效。
java.exe
,其实至少有三个线程:main()主线程,gc() 垃圾回收线程,异常处理线程
。当然如果发生异常,会影响主线程。多线程的优点
多线程的使用场景;
new
关键字和 Thread
类或其子类建立一个线程对象后,该线程对象就处于新建状态。此时线程并没有开始执行。它保持这个状态直到程序 start()
这个线程。start()
方法之后,该线程就进入就绪状态。就绪状态的线程处于就绪队列中,要等待JVM里线程调度器的调度。此时线程还是没有开始执行。CPU
资源,就可以执行run()
,此时线程开始执行,处于运行状态,运行状态的线程最为复杂,可以变为阻塞状态,就绪状态和消亡状态补充:线程的阻塞状态
sleep
睡眠,suspend
(挂起)等方法,在线程失去所占用的资源后,该线程就成运行状态进入阻塞状态,在睡眠时间完毕或者获得设备资源之后,就可以重新进入就绪状态补充:线程的阻塞状态分为三种:
wait()
方法,使得线程进入等待阻塞状态synchronized
同步锁失败(因为同步锁被其他线程占用)sleep()
或join()
发出了I/O请求时,线程就会进入阻塞状态,当sleep()
状态超时时,join()
等待线程终止或超时,或者I/O处理完毕,线程重新转入就绪状态补充:线程的消亡状态
创建方式
Callable
和Future
创建线程继承方式和实现方式的区别:
Thread
:线程代码存放Thread
子类run
方法中。Runnable
:线程代码存在接口的子类的run
方法。实现方式的好处:
Runnable
,一个类只需要执行一个方法调用run()
:public void run()
,可以重写run
方法,同时 run()
可以调用其他方法,使用其他类,并声明变量,就像主线程一样。start()
方法运行新县城方式一:实现Runnable接口
Runnable
接口。Runnable
接口中的run
方法。Thread
类含参构造器创建线程对象。Runnable
接口的子类对象作为实际参数传递给Thread
类的构造器中。Thread
类的start
方法:开启线程,调用Runnable
子类接口的run
方法。package com.company;
// Java_线程样例 使用 Runnable 接口实现线程
public class Java_27 {
public static void main(String args[]) {
RunnableDemo R1 = new RunnableDemo( "Thread-1");
R1.start();
RunnableDemo R2 = new RunnableDemo( "Thread-2");
R2.start();
}
}
class RunnableDemo implements Runnable {
private Thread t;
private String threadName;
RunnableDemo( String name) {
threadName = name;
System.out.println("创建线程 " + threadName );
}
public void run() {
System.out.println("启动线程 " + threadName );
try {
for(int i = 4; i > 0; i--) {
System.out.println("线程执行: " + threadName + ", " + i);
// 让线程睡眠一会
Thread.sleep(50);
}
}catch (InterruptedException e) {
System.out.println("线程执行出现异常 " + threadName + " interrupted.");
}
System.out.println("线程执行 " + threadName + " exiting.");
}
public void start () {
System.out.println("开始执行线程 " + threadName );
if (t == null) {
t = new Thread (this, threadName);
t.start ();
}
}
}
Thread
类,然后创建类的实例Thread
的类必须重写run()
方法,run()
方法是新线程的入口点,继承Thread
的类新建的线程也必须通过start()
方法启动Thread
创建线程尽管被列为一种多线程实现方式,但是本质上也是实现了Runnable
接口的一个实例。方式二:继承Thread类:
Thread
类。Thread
类中的run
方法Thread
子类对象,即创建了线程对象。start
方法:启动线程,调用run
方法注意:
run()
方法,那么就只是普通方法,没有启动多线程模式。run()
方法由JVM调用,什么时候调用,执行的过程控制都有操作系统的CPU调度决定。start
方法。start()
方法启动,如果重复调用了,则将抛出以上的异常“IllegalThreadStateException
”。package com.company;
// 通过继承 Thread 类的方式新建一个线程
public class Java_28 {
public static void main(String args[]) {
ThreadDemo T1 = new ThreadDemo( "Thread-1");
T1.start();
ThreadDemo T2 = new ThreadDemo( "Thread-2");
T2.start();
}
}
class ThreadDemo extends Thread {
private Thread t;
private String threadName;
ThreadDemo( String name) {
threadName = name;
System.out.println("创建线程 " + threadName );
}
public void run() {
System.out.println("执行线程 " + threadName );
try {
for(int i = 4; i > 0; i--) {
System.out.println("线程名为: " + threadName + ", " + i);
// 让线程睡眠一会
Thread.sleep(50);
}
}catch (InterruptedException e) {
System.out.println("线程出现异常 " + threadName + " interrupted.");
}
System.out.println("线程名为 " + threadName + " exiting.");
}
public void start () {
System.out.println("启动线程 " + threadName );
if (t == null) {
t = new Thread (this, threadName);
t.start ();
}
}
}
JVM
允许程序运行多个线程,它通过java.lang.Thread
类来体现。Thread
对象的run()
方法来完成操作的,经常run()
方法的主体称为线程体Thread对象的start()
方法来启动这个线程,而非直接调用run()
调用线程的重要方法
暂停线程的重要方法
1-10
之间的数字表示,在Thread类中定义的三个常量:
public static int MIN_PRIORITY
public static int NORM_PRIORITY
public static int MAX_PRIORITY
5(NORM_PRIORITY)
。 MIN_PRIORITY的值为1
,MAX_PRIORITY的值为10。
package com.company;
// 线程的优先级
public class Java_29 {
public static void main(String args[]) {
TestMultiPriority1 m1 = new TestMultiPriority1();
TestMultiPriority1 m2 = new TestMultiPriority1();
m1.setPriority(Thread.MIN_PRIORITY);
m2.setPriority(Thread.MAX_PRIORITY);
m1.start();
m2.start();
}
}
class TestMultiPriority1 extends Thread {
public void run() {
System.out.println("正在运行的线程名:" + Thread.currentThread().getName());
System.out.println("正在运行的线程的优先级:" + Thread.currentThread().getPriority());
}
}
线程池的优点:线程池提供了更好的新能,因为不需要重新创建新线程,所以节省了时间
在Servlet和JSP中使用线程池,容器创建一个线程来处理请求
package com.company;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
// 线程池实例
class WorkerThread implements Runnable {
private String message;
public WorkerThread(String s) {
this.message = s;
}
public void run() {
System.out.println(Thread.currentThread().getName() + " 开始信息 = " + message);
processmessage();// call processmessage method that sleeps the thread for 2 seconds
System.out.println(Thread.currentThread().getName() + " 结束");// prints thread name
}
private void processmessage() {
try {
Thread.sleep(2000); // 休眠 2 秒
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
public class Java_30 {
public static void main(String[] args) {
ExecutorService executor = Executors.newFixedThreadPool(5);//creating a pool of 5 threads
for (int i = 0; i < 10; i++) {
Runnable worker = new WorkerThread("" + i);
executor.execute(worker);//calling execute method of ExecutorService
}
executor.shutdown();
while (!executor.isTerminated()) { }
System.out.println("所有线程执行完毕");
}
}
Executor
:线程池顶级接口ExecutorService
:线程池接口,可通过submit(Runnable task)
提交任务。Executors
工具类:通过此类可以获得一个线程池。newFixedThreadPool(int nThreads)
:获取固定数量的线程池。参数:指定线程池中线程的数量。newCashedThreadPool()
:获得动态数量的线程池,如不够则重新创建新的,没有上限。package com.company;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
// 线程池实例二 :详细使用线程池
public class Java_31 {
public static void main(String[] args){
//创建固定个数的线程池
// ExecutorService es=Executors.newFixedThreadPool(5);
//创建动态线程池
ExecutorService es= Executors.newCachedThreadPool();
//创建单线程线程池
//Executors.newSingleThreadExecutor();
//创建调度线程池
//Executors.newScheduledThreadPool();
// 创建任务
Runnable runnable=new Runnable() {
private int ticket=100;
@Override
public void run() {
while (true){
if (ticket<=0){
break;
}
System.out.println(Thread.currentThread().getName()+"卖了第"+ticket+"张票");
ticket--;
}
}
};
//提交任务
for (int i =0;i<5;i++){//5=上面的线程池个数
es.submit(runnable);
}
//关闭线程池
es.shutdown();
}
}
Callable
接口的实现类,并实现call()
方法,该call()
方法将作为线程执行体,并且有返回值。Callable
实现类的实例,使用 FutureTask
类来包装 Callable
对象,该 FutureTask
对象封装了该 Callable 对象的 call()
方法的返回值。FutureTask
对象作为 Thread 对象的 target
创建并启动新线程。FutureTask
对象的 get()
方法来获得子线程执行结束后的返回值。Callable接口:
Callable接口 与Runnable接口
类似,实现之后代表一个接口任务。Callable具有泛型返回值,可以声明异常
package com.company;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.FutureTask;
// Callable 接口样例
/**
* 演示Callable接口的使用
* Callable与Runnable接口的区别:
* 1、Callable中call方法具有泛型返回值、Runnable接口中run方法没有返回值
* 2、Callable中call方法可以声明异常,Runnable接口中run方法没有异常
*/
public class Java_33 {
public static void main(String[] args) throws ExecutionException, InterruptedException {
//功能需求,使用Callable实现1-10的和
//1、创建Callable对象
Callable callable=new Callable() {
@Override
public Integer call() throws Exception {
System.out.println(Thread.currentThread().getName()+"开始计算");
int sum=0;
for (int i=0;i<=10;i++){
sum+=i;
}
return sum;
}
};
//把Callable对象转成任务
FutureTask task=new FutureTask<>(callable);
//创建线程
Thread thread=new Thread(task);
thread.start();
//获取结果
Integer sum = task.get();
System.out.println("计算结果是:"+sum);
}
}
Future接口:表示将要完成任务的结果
线程池+Callable接口+Future+接口的综合使用
package com.company;
import java.util.concurrent.*;
// 线程池+Callable+Future+接口的综合使用
/**
* 要求:计算1-100的和
* 使用两个线程,并发计算1-50、51-100的和,再进行汇总统计。
*/
public class Java_34 {
public static void main(String[] args) throws ExecutionException, InterruptedException {
//创建线程池
ExecutorService es = Executors.newFixedThreadPool(2);
//提交任务
Future future=es.submit(new Callable() {
private int sum=0;
@Override
public Integer call() throws Exception {
System.out.println(Thread.currentThread().getName()+"开始计算");
for (int i=0;i<=50;i++){
sum+=i;
}
return sum;
}
});
Future future2=es.submit(new Callable() {
private int sum=0;
@Override
public Integer call() throws Exception {
System.out.println(Thread.currentThread().getName()+"开始计算");
for (int i=51;i<=100;i++){
sum+=i;
}
return sum;
}
});
//汇总
int sum=future.get()+future2.get();
System.out.println("计算结果是:"+sum);
}
}