回顾
操作系统:
-硬件(冯诺依曼体系系统)
-软件(OS操作系统)内核部分(内核态)、用户部分(用户态)
进程:系统分配资源的最小单位
单进程程序->多进程程序
线程:系统调度的最小单位
(优点:创建的时候占用更少的资源,并且多个线程之间可以共享资源)
线程共享的资源:
- 打开的文件
- 共享内存
进程VS线程
- 进程:系统分配资源的最小单位,线程:系统调度的最小单位
- 一个进程至少要包含一个线程
- 线程必须要依附于进程,线程是进程实质工作的一个最小单位
线程
创建线程的方式:
- 继承Thread类是实现线程创建方式
public class Thread1 {
static class MyThread extends Thread {
@Override
public void run() {
//线程执行任务
System.out.println("线程名称"+Thread.currentThread().getName());
}
}
public static void main(String[] args) {
//创建线程
Thread t1 = new MyThread();
//运行新线程
t1.start();
System.out.println("当前线程名称(主线程)"+Thread.currentThread().getName());
}
}
public class Thread2 {
public static void main(String[] args) {
Thread thread = new Thread(){
@Override
public void run() {
System.out.println("线程名称"+Thread.currentThread().getName());
}
};
thread.start();
}
}
继承Thread的缺点:Java语言的设计当中只能实现单继承,如果继承了Thread类,就不能继承其他类,所以引入了接口,接口可以实现多个
- 实现Runnable接口的方式
public class Thread3 {
static class MyRunnable implements Runnable {
@Override
public void run() {
System.out.println("线程名称" + Thread.currentThread().getName());
}
}
public static void main(String[] args) {
//1.新建Runnable类
MyRunnable runnable = new MyRunnable();
//2.新建Thread
Thread thread = new Thread(runnable);
//3.启动线程
thread.start();
}
}
public class Thread4 {
/**
* 常用!
* @param args
*/
public static void main(String[] args) {
//匿名内部类的方式实现线程
Thread thread = new Thread(new Runnable() {
@Override
public void run() {
System.out.println("线程名称" + Thread.currentThread().getName());
}
});
thread.start();
}
}
public class Thread5 {
public static void main(String[] args) {
//lambda + 匿名 runnable 实现方式
Thread thread = new Thread(() -> {
System.out.println("线程名称" + Thread.currentThread().getName());
});
thread.start();
}
}
- 实现Callable接口的方式(可以得到线程执行之后的结果)
public class Thread6 {
static class MyCallable implements Callable<Integer> {
@Override
public Integer call() throws Exception {
//生成一个随机数
int num = new Random().nextInt(10);
System.out.println("子线程名称" + Thread.currentThread().getName() + ",随机数" + num);
return num;
}
}
public static void main(String[] args) throws ExecutionException, InterruptedException {
//1.创建一个Callable
MyCallable myCallable = new MyCallable();
//2.创建一个FutureTask对象来接收返回值
FutureTask<Integer> futureTask = new FutureTask<>(myCallable);
//3.创建Thread
Thread thread = new Thread(futureTask);
//启动线程
thread.start();
//得到线程执行结果
int result = futureTask.get();
System.out.println(String.format("线程名称:%s,数字:%d",
Thread.currentThread().getName(), result));
}
}
线程休眠
- 方法1:
Thread.sleep(1000);
- 方法2:
TimeUnit.SECONDS.sleep(1);
- 方法3:
Thread.sleep(TimeUnit.SECONDS.toMillis(1));
使用两个线程打印“AABBCCDD”?
public static void main(String[] args) throws InterruptedException {
Thread thread = new Thread(new Runnable() {
@Override
public void run() {
String str = "ABCD";
for (char a:str.toCharArray()) {
System.out.print(a);
try {
Thread.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
});
Thread t1 = new Thread(thread);
Thread t2 = new Thread(thread);
t1.start();
t2.start();
}
线程分组
可以将一类线程归为一组,并且进行信息打印,查看一组线程的具体行为
线程优先级:
新创建的线程默认优先级为:5
优先级最大为10,最小为1(取值为1-10)值越大,执行权重就越高
优先级越高执行的优先级越高,执行权重越大,但是CPU的调度复杂的不行,不会严格按照优先级排序来执行,但是总体还是符合的
线程分类:
- 后台线程(守护线程)
- 用户线程(默认线程)
守护线程是用来服务用户线程,用户线程-顾客,服务线程-服务员
进程退出:没有用户线程运行,进程就会结束
守护线程使用场景:Java垃圾回收机
注意:
- 守护线程设置前必须调用
start()
,如果设置守护线程在开始线程之后,程序会报错,并且设置的守护线程不会生效 - 在守护线程里边创建的线程,默认为守护线程