概述
面试题:进程和线程的区别?
进程是操作系统资源分配的基本单位,而线程是处理器任务调度和执行的基本单位。
一个进程可以包含多个线程,而且至少包含一个线程。
地址空间:进程有自己独立的地址空间,每启动一个进程,系统都会为其分配地址空间,
线程没有独立的地址空间,同一进程的线程共享本进程的地址空间。
资源拥有:进程之间的资源是独立的,同一进程内的线程共享本进程的资源。
执行过程:每个独立的进程有一个程序运行的入口、程序执行序列和程序入口。
但是线程不能独立执行,必须依附在应用程序中,由应用程序提供多个线程执行控制。
面试题:怎么启动一个线程?调用run方法和start方法有什么区别?
调用start方法来启动线程。
run方法用来定义线程要执行的任务,如果直接调用run方法就是将其当作普通方法来调用,
程序会顺序执行,要等run方法的方法体执行完毕后才可以继续执行下面的代码;
start方法用来开启一个线程,会将该线程纳入到线程调度程序中,等待CPU分配时间片再运行,
运行时会自动调用run方法,但是无需等待run方法的方法体执行完毕也可以执行其他内容。
创建线程有几种方式,有什么区别呢?
创建线程有三种方式:
1)继承Thread类创建线程
2)实现Runnable接口创建线程
3)使用Callable和Future创建线程
区别:
第二种和第三种的区别:
实现Runnable接口和实现Callable接口的方式基本相同,不过是实现Callable接口执行call()方法有返回值,实现Runnable接口线程执行体run()方法无返回值
第一种和第二种、第三种的区别:
1.继承Thread类后不能再继承其他类去复用方法
2.实现Runnable接口和实现Callable接口还可以实现其它接口或者继承其它的类
package thread;
/*
面试题:进程和线程的区别?
进程是操作系统资源分配的基本单位,而线程是处理器任务调度和执行的基本单位。
一个进程可以包含多个线程,而且至少包含一个线程。
地址空间:进程有自己独立的地址空间,每启动一个进程,系统都会为其分配地址空间,
线程没有独立的地址空间,同一进程的线程共享本进程的地址空间。
资源拥有:进程之间的资源是独立的,同一进程内的线程共享本进程的资源。
执行过程:每个独立的进程有一个程序运行的入口、程序执行序列和程序入口。
但是线程不能独立执行,必须依附在应用程序中,由应用程序提供多个线程执行控制。
*/
/*
面试题:怎么启动一个线程?调用run方法和start方法有什么区别?
调用start方法来启动线程。
run方法用来定义线程要执行的任务,如果直接调用run方法就是将其当作普通方法来调用,
程序会顺序执行,要等run方法的方法体执行完毕后才可以继续执行下面的代码;
start方法用来开启一个线程,会将该线程纳入到线程调度程序中,等待CPU分配时间片再运行,
运行时会自动调用run方法,但是无需等待run方法的方法体执行完毕也可以执行其他内容。
*/
/**
* 多线程
* 线程:一个顺序的 单一的 程序执行流程就是一个线程。
* 多线程:多个单一 顺序执行 的流程并发运行。
*
* 多个线程实际运行是走走停停的,线程调度程序会将CPU运行时间划分为若干时间片段
* 并尽可能均匀的分配给每个线程,拿到时间片的线程会被CPU执行这段时间。
* 当超时后,线程调度程序会再次分配一个时间片段给一个线程,使得CPU执行它。
* 如此反复。由于CPU执行时间在纳秒级别,所以我们感觉不到切换线程运行的过程。
* 所以微观上走走停停,宏观上感觉一起运行的现象称为并发运行。
*
* 创建线程的第一种方式:
* 定义一个类继承自Thread,并重写run方法,在run方法中定义要与其他线程并发运行的任务。
* 调用start方法启动线程。
*
* CPU是一个处理器 i5、i7、i9
*
* @author YanLy
* @date 2021/6/1 11:30
*/
public class ThreadDemo1 {
public static void main(String[] args) {
// 1.实例化线程
Thread t1 = new MyThread1();
Thread t2 = new MyThread2();
// 2.启动线程 -- 不能直接调用run方法!! -- 调用run方法是单纯的调方法 和线程无关
// start方法调用后,线程纳入线程调度程序控制,run会自动执行。
t1.start();
t2.start();
}
}
/*
第一种创建线程的方式优点在于结构简单,便于匿名内部类形式创建。
缺点:
1.直接继承线程,会导致不能再继承其他类去复用方法,这在实际开发中是非常不方便的。
2.定义线程的同时重写了run方法,会导致线程与线程任务绑定在一起,不利于线程的重用。
*/
class MyThread1 extends Thread{
@Override
public void run() {
for (int i = 0; i < 1000; i++) {
System.out.println("你瞅啥?");
}
}
}
class MyThread2 extends Thread{
@Override
public void run() {
for (int i = 0; i < 1000; i++) {
System.out.println("瞅你咋滴!");
}
}
}
package thread;
/**
* 创建线程的第二种方式:
* 实现Runnable接口单独定义线程任务
*
* @author YanLy
* @date 2021/6/1 14:16
*/
public class ThreadDemo2 {
public static void main(String[] args) {
// 1.创建线程要执行的任务
Runnable r1 = new MyRunnable1();
Runnable r2 = new MyRunnable2();
// 2.创建两个线程分别执行任务
Thread t1 = new Thread(r1);
Thread t2 = new Thread(r2);
/*
线程和任务分离开了,线程和任务的耦合度降低,更灵活
*/
// 3.启动线程
t1.start();
t2.start();
}
}
class MyRunnable1 implements Runnable{
@Override
public void run() {
for (int i = 0; i < 1000; i++) {
System.out.println("早啊,海绵宝宝~");
}
}
}
class MyRunnable2 implements Runnable{
@Override
public void run() {
for (int i = 0; i < 1000; i++) {
System.out.println("早上好!派大星~");
}
}
}
package thread;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.FutureTask;
/**
* 第三种创建线程的方式
* 实现Callable接口定义要执行的任务
* 需要重写call方法,call方法有返回值,也可以抛出异常。
*
* Callable接口的实例不能直接作为Thread实例的参数,需要搭配Future接口一块使用,
* FutureTask是Future的实现类,可以对Runnable或者Callable的任务执行取消、
* 查询、获取结果等操作。
*
* Callable接口和Future接口是JDK5以后开始提供的。
*
* @author YanLy
* @date 2021/6/1 14:35
*/
public class ThreadDemo3 {
public static void main(String[] args) throws ExecutionException, InterruptedException {
Callable c1 = new MyCallable1();
Callable c2 = new MyCallable2();
FutureTask f1 = new FutureTask(c1);
FutureTask f2 = new FutureTask(c2);
Thread t1 = new Thread(f1);
Thread t2 = new Thread(f2);
t1.start();
t2.start();
//获取call方法的返回值
String s1 = (String) f1.get();
String s2 = (String) f2.get();
System.out.println(s1);
System.out.println(s2);
}
}
class MyCallable1 implements Callable{
@Override
public Object call() throws Exception {
for (int i = 0; i <1000; i++) {
System.out.println("今天你学废了吗?");
}
return "MyCallable1";
}
}
class MyCallable2 implements Callable{
@Override
public Object call() throws Exception {
for (int i = 0; i <1000; i++) {
System.out.println("学不会啦");
}
return "MyCallable2";
}
}
package thread;
import java.util.concurrent.Callable;
import java.util.concurrent.FutureTask;
/**
* 使用匿名内部类完成线程的创建
*
* @author YanLy
* @date 2021/6/1 15:19
*/
public class ThreadDemo4 {
public static void main(String[] args) {
// 第一种创建线程的方法
Thread t = new Thread(){
@Override
public void run() {
for (int i = 0; i < 1000; i++) {
System.out.println("Thread");
}
}
};
t.start();
// 第二种创建线程的方法
Runnable r = new Runnable(){
@Override
public void run() {
for (int i = 0; i < 1000; i++) {
System.out.println("Runnable");
}
}
};
// lambda表达式
Runnable r2 = ()->{
for (int i = 0; i < 1000; i++) {
System.out.println("Runnable-lambda");
}
};
// 如果只有一句代码可以省略大括号
Runnable r3 = ()-> System.out.println("Runnable-lambda-only");
// 第三种创建线程的方法
Callable c = new Callable(){
@Override
public Object call() throws Exception {
for (int i = 0; i < 1000; i++) {
System.out.println("Callable");
}
return null;
}
};
FutureTask f = new FutureTask(c);
Thread t1 = new Thread(f);
// lambda表达式
Callable c1 = ()->{
for (int i = 0; i < 1000; i++) {
System.out.println("Callable");
}
return null;
};
// 如果只有一句代码可以省略大括号
Callable c2 = ()->null;
}
}
package thread;
import java.util.Scanner;
/**
* 线程提供了一个静态方法:
* static void sleep(long ms)
* 使调用该方法的线程进入阻塞状态指定毫秒。超时后线程会自动回到RUNNABLE状态,
* 等待再次获取时间片并发运行。
*
* @author YanLy
* @date 2021/6/1 15:46
*/
public class SleepDemo {
// InterruptedException 被中断异常
public static void main(String[] args){
/*
实现倒计时程序:
程序启动后要求用户输入一个数字,然后从这个数字开始每秒递减,
到0时输出"时间到",程序结束
*/
Scanner scanner = new Scanner(System.in);
System.out.println("请输入一个数字");
int num = scanner.nextInt();
while(num>0){
System.out.println(num--);
/*
sleep方法要求我们必须处理中断异常:InterruptedException
当一个线程调用sleep方法处于阻塞的过程中,该线程的Interrupt方法
被调用时会中断它的sleep阻塞,并抛出上述异常。
*/
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println("时间到!");
}
}
package thread;
// InterruptedException 中断异常
/**
* sleep方法要求我们必须处理中断异常:InterruptedException
* 当一个线程调用sleep方法处于阻塞的过程中,该线程的Interrupt方法
* 被调用时会中断它的sleep阻塞,并抛出上述异常。
*
* @author YanLy
* @date 2021/6/1 16:14
*/
public class SleepDemo2 {
public static void main(String[] args) {
Thread lin = new Thread(){
@Override
public void run() {
System.out.println("林:正在打扫...");
try {
Thread.sleep(100000000);
} catch (InterruptedException e) {
System.out.println("林:干嘛呢!干嘛呢!");
}
}
};
Thread huang = new Thread(){
@Override
public void run() {
System.out.println("开始砸墙!");
for (int i = 0; i < 5; i++) {
System.out.println("黄:80!");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println("哐当!!!");
System.out.println("黄:搞定!");
lin.interrupt();// 中断lin线程的睡眠阻塞
}
};
lin.start();
huang.start();
}
}
package thread;
/**
* 线程提供了一个方法:
* void join()
* 该方法允许调用这个方法的线程在该方法所属线程上等待(阻塞),直到该方法所属线程结束后才会解除等待,
* 继续后续的工作,所以join方法可以用来协调线程的同步运行。
*
* 同步:多个线程执行过程存在先后顺序进行
* 异步:多个线程各干各的 -- 线程本身就是异步运行的
*
* @author YanLy
* @date 2021/6/1 16:31
*/
public class JoinDemo {
// 标识图片是否下载完毕
static boolean isFinish = false;
public static void main(String[] args) {
/*
当一个方法的局部内部类中引用了这个方法的其他局部变量时,
这个变量必须是final的,这是由于JVM内存分配问题导致的,当成语法要求去遵守即可。
因此被局部内部类引用的局部变量是不能被二次赋值的。
*/
// boolean isFinish = false;
Thread download = new Thread(){
@Override
public void run() {
System.out.println("download:开始下载图片...");
for (int i = 0; i < 100; i++) {
System.out.println("download:"+i+"%");
try {
Thread.sleep(50);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println("download:图片下载完毕!");
isFinish = true;
}
};
Thread show = new Thread(){
@Override
public void run() {
System.out.println("show:正在显示图片...");
try {
// show开始阻塞,知道download执行完毕再继续后续的操作
// 保证download先运行
download.join(); // join加入 把时间片分配给download 等download加载完再执行自己的
} catch (InterruptedException e) {
e.printStackTrace();
}
if (!isFinish){
// 当一个线程的run方法抛出一个异常,则线程会结束
throw new RuntimeException("show:图片显示失败!");
}
System.out.println("show:图片显示成功");
}
};
download.start();
show.start();
}
}
package thread;
/**
* java中所有的代码都是靠线程运行的,main方法也不例外。
* java程序开始运行时,JVM会创建一条线程来执行main方法,
* 这条运行main方法的线程的名字叫做"main",也称为主线程
*
* 线程提供了一个静态方法,可以获取到运行该方法的线程
* static Thread currentThread() -- 获取到当前的线程 current 当前的
*
* @author YanLy
* @date 2021/6/1 17:16
*/
public class CurrentThreadDemo {
public static void main(String[] args) {
// 获取到运行main方法的线程
Thread main = Thread.currentThread();
System.out.println("运行main方法的线程是:" + main);
// Thread[main,5,main] -- [线程名称,线程优先级,线程所属线程组]
// 5 -- 优先级 -- 默认都是 5
// 在主线程上再创建一条线程,让它并发运行
Thread t = new Thread(){
@Override
public void run() {
// 获取运行当前run方法的线程
Thread t = Thread.currentThread();
System.out.println("运行run方法的线程是:"+t);
// Thread[Thread-0,5,main] -- [线程名称,线程优先级,线程所属线程组]
doSome(); // 让t线程调用doSome方法
// Thread[Thread-0,5,main] -- [线程名称,线程优先级,线程所属线程组]
}
};
t.start(); // 当t线程调用start方法以后,就与主线程并发了。
doSome();// 让主线程执行doSome方法
// main方法的线程和我们自己建的线程是并发运行,不一定会先运行谁。所以与放置位置无关
}
public static void doSome(){
Thread t = Thread.currentThread();
System.out.println("运行doSome方法的线程是:" + t);
}
}
package thread;
/**
* 线程的优先级
* 线程有10个优先级,使用整数1-10表示
* 1为最低优先级,10为最高优先级,5为默认值。
*
* 线程start方法后会纳入线程调度器中统一管理,线程只能被动的被分配时间片并发运行,
* 而无法主动索取时间片,线程调度器会尽可能均匀的将时间片分配给每个线程。
* 调整线程的优先级可以最大程度的干涉获取时间片的几率,
* 优先级越高的线程获取时间片的次数越多,反之则越少(前提是这些线程在同一个CPU核心上)。
*
* CPU在版本之上分几核
* 由于现在的电脑都是多核的电脑,所以设置优先级效果并不明显,只是尽量。
*
* @author YanLy
* @date 2021/6/1 17:37
*/
public class PriorityDemo {
public static void main(String[] args) {
Thread min = new Thread(){
@Override
public void run() {
for (int i = 0; i < 1000; i++) {
System.out.println("min");
}
}
};
Thread normal = new Thread(){
@Override
public void run() {
for (int i = 0; i < 1000; i++) {
System.out.println("normal");
}
}
};
Thread max = new Thread(){
@Override
public void run() {
for (int i = 0; i < 1000; i++) {
System.out.println("max");
}
}
};
// 设置线程优先级
min.setPriority(Thread.MIN_PRIORITY);//最小
max.setPriority(Thread.MAX_PRIORITY);//最大
// 开启线程
min.start();
normal.start();
max.start();
}
}
最后
以上就是内向画笔为你收集整理的创建线程的三种方式,线程的方法,线程的优先级的全部内容,希望文章能够帮你解决创建线程的三种方式,线程的方法,线程的优先级所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
发表评论 取消回复