1、进程和线程的区别
进程和线程的由来
- 串行:初期的计算机智能串行执行任务,并且需要长时间等待用户输入
- 批处理:预先将用户的指令集中成清单,批量串行处理用户指令.仍然无法并发执行
- 进程:进程独占内存空间。保存各自运行状态,相互间不干扰且可以互相切换,为并发处理任务提供了可能
- 线程:共享进程的内存资源。相互间切换更快速,支持更细粒度的任务控制,使进程内的子任务得以并发执行
进程是资源分配的最小单位,线程是CPU调度的最小单位
- 所有与进程相关的资源,都被记录在PCB中
- 进程是抢占处理机的调度单位;线程属于某个进程,共享其资源
- 线程只由堆栈寄存器、程序计数器和TCB组成
总结
- 线程不能看做独立应用,而进程可看做独立应用
- 进程有独立的地址空间,相互不影响,线程只是进程的不同执行路径
- 线程没有独立的地址空间,多进程的程序比多线程程序健壮
- 进程的切换比线程的切换开销大
Java进程和线程的关系
- Java对操作系统提供的功能进行封装,包括进程和线程
- 运行一个程序会产生一个进程,进程包含至少-个线程
- 每个进程对应一个JVM实例,多个线程共享JVM里的堆
- Java采用单线程编程模型,程序会自动创建主线程
- 主线程可以创建子线程,原则上要后于子线程完成执行
java是具有主线程的:
public class CurrentThreadDemo {
public static void main(String[] args) {
System.out.println("Current Thread: " + Thread.currentThread().getName());
}
}
2、Thread中的start和run方法的区别
- 调用start()方法会创建一个新的子线程并启动
- run()方法只是Thread的一 个普通方法的调用
示例代码:
public class ThreadTest {
private static void attack() {
System.out.println("Fight");
System.out.println("Current Thread is : " + Thread.currentThread().getName());
}
public static void main(String[] args) throws InterruptedException {
Thread t = new Thread(){
public void run(){
attack();
}
};
System.out.println("current main thread is : " + Thread.currentThread().getName());
t.run(); // min
t.start(); // Thread-0
}
}
运行结果:
current main thread is : main
Fight
Current Thread is : main
Fight
Current Thread is : Thread-0
使用start是调用外部类:
在openjdk
网页中查找源码(链接🔗):
从Tread.c
文件中查找start0
,发现引入了jvm
文件,再去查询对应的方法(链接🔗):
3、Thread和Runnable是什么关系
- Thread是实现了 Runnable接口的类,使得run支持多线程
- 因类的单一继承原则,推荐多使用Runnable接口
示例代码:
- Thread示例
Thred主类:public class MyThread extends Thread { private String name; public MyThread(String name){ this.name = name; } @Override public void run(){ for(int i = 0 ; i < 10 ; i ++){ System.out.println("Thread start : " + this.name + ",i= " + i); } } }
运行结果:public class ThreadDemo { public static void main(String[] args) { MyThread mt1 = new MyThread("Thread1"); MyThread mt2 = new MyThread("Thread2"); MyThread mt3 = new MyThread("Thread3"); mt1.start(); mt2.start(); mt3.start(); } }
Thread start : Thread1,i= 0 Thread start : Thread3,i= 0 Thread start : Thread3,i= 1 Thread start : Thread2,i= 0 Thread start : Thread3,i= 2 Thread start : Thread1,i= 1 Thread start : Thread2,i= 1 Thread start : Thread3,i= 3 Thread start : Thread2,i= 2 ......
- Runnable示例
Runable主类public class MyRunnable implements Runnable { private String name; public MyRunnable(String name){ this.name = name; } @Override public void run(){ for(int i = 0 ; i < 10 ; i ++){ System.out.println("Thread start : " + this.name + ",i= " + i); } } }
运行结果:public class RunnableDemo { public static void main(String[] args) throws InterruptedException { MyRunnable mr1 = new MyRunnable("Runnable1"); MyRunnable mr2 = new MyRunnable("Runnable2"); MyRunnable mr3 = new MyRunnable("Runnable3"); Thread t1 = new Thread(mr1); Thread t2 = new Thread(mr2); Thread t3 = new Thread(mr3); t1.start(); t2.start(); t3.start(); } }
Thread start : Runnable2,i= 0 Thread start : Runnable3,i= 0 Thread start : Runnable3,i= 1 Thread start : Runnable1,i= 0 Thread start : Runnable1,i= 1 Thread start : Runnable1,i= 2 ......
如何给run()方法传参(研究一下)
实现的方式主要有三种
- 构造函数传参
- 成员变量传参
- 回调函数传参
如何实现处理线程的返回值
实现的方式主要有三种
主线程等待法
实现简单,但是需要自己实现循环等待的逻辑,当需要等待的变量越多,代码将显得越臃肿,没法进行精准控制
使用Thread类的join()阻塞当前线程以等待子线程处理完毕
比上一个方法简单,但是粒度不够细,
示例代码:
public class CycleWait implements Runnable{ private String value; public void run() { try { Thread.currentThread().sleep(5000); } catch (InterruptedException e) { e.printStackTrace(); } value = "we have data now"; } public static void main(String[] args) throws InterruptedException { CycleWait cw = new CycleWait(); Thread t = new Thread(cw); t.start(); // 如果没有以下两种方法,则在线程执行是先打印value值,而不是先等待线程然后赋值,导致程序一运行打印value:null /* 主线程等待法,需要判断线程实例中的valu是否为空,当为空的时候等待100毫秒,直到线程完成,最后打印 */ while (cw.value == null){ Thread.currentThread().sleep(100); } /* 阻塞当前线程以等待子线程处理完毕,最后打印 */ // t.join(); System.out.println("value : " + cw.value); } }
运行结果:
value : we have data now
通过Callable接口实现:通过FutureTask Or线程池获取
示例代码:
Callable接口实现
import java.util.concurrent.Callable;
public class MyCallable implements Callable<String> {
@Override
public String call() throws Exception{
String value="test";
System.out.println("Ready to work");
Thread.currentThread().sleep(5000);
System.out.println("task done");
return value;
}
}
- 通过FutureTask获取
import java.util.concurrent.ExecutionException;
import java.util.concurrent.FutureTask;
public class FutureTaskDemo {
public static void main(String[] args) throws ExecutionException, InterruptedException {
FutureTask<String> task = new FutureTask<String>(new MyCallable());
new Thread(task).start();
if(!task.isDone()){
System.out.println("task has not finished, please wait!");
}
System.out.println("task return: " + task.get());
}
}
运行结果:
task has not finished, please wait!
Ready to work
task done
task return: test
- 通过线程池获取
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
public class ThreadPoolDemo {
public static void main(String[] args) {
ExecutorService newCachedThreadPool = Executors.newCachedThreadPool();
Future<String> future = newCachedThreadPool.submit(new MyCallable());
if(!future.isDone()){
System.out.println("task has not finished, please wait!");
}
try {
System.out.println(future.get());
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
} finally {
newCachedThreadPool.shutdown();
}
}
}
运行结果:
task has not finished, please wait!
Ready to work
task done
test