线程与进程
进程是指一个内存中运行的应用程序,每个进程都有一个独立的内存空间。 线程是进程中的一个执行路径,共享一个内存空间,线程之间可以自由切换,并发执行,一个进程最少有一个线程。
线程不安全
在多个线程并发环境下,多个线程共同访问同一共享内存资源时,其中一个线程对资源进行写操作的中途(写⼊入已经开始,但还没结束),其他线程对这个写了一半的资源进⾏了读操作,或者对这个写了一半的资源进⾏了写操作,导致此资源出现数据错误,即线程不安全。
JMM
在Java内存模型中,分为主内存和线程工作内存,线程使用共享数据时,都是先从主内存中拷贝到工作内存,使用完成之后再写入主内存,可以理解为线程之间通讯是通过共享内存的方式实现的。
多线程
Thread
继承Thread类就是线程类。每个线程都有自己的栈空间,共用一个堆内存。
new Thread(
() -> System.out.println(Thread.currentThread().getName())
).start();
Thread常用方法
- run
run方法就是线程要执行的任务方法,即是一条新的执行路径,该路径的触发方 法不是调用run方法,而是Thread类的 start 方法来启动任务。
start启动一个线程来运行run方法。 - start
start方法用来启动一个线程,当调用start方法后,系统才会开启一个新的线程来执行用户定义的子任务,在这个过程中,会为相应的线程分配需要的资源。 - currentThread
当前正在运行的进程。 - getName和setName
用来得到或者设置线程名称。 - sleep
sleep 相当于让线程睡眠,交出CPU,让CPU去执行其他的任务。 如果需要让当前正在执行的线程暂停一段时间,并进入阻塞状态,则可以通过调用Thread类的静态sleep()方法来实现。
当线程调用sleep()方法进入阻塞状态后,在其睡眠时间内,该线程不会获得执行机会,即使系统中没有其他可执行线程,处于sleep()中的线程也不会执行,因此sleep()方法常用来暂停程序的执行。
但是有一点要非常注意,sleep方法不会释放锁,也就是说如果当前线程持有对某个对象的锁,则即使调用sleep方法,其他线程也无法访问这个对象。 - setDaemon()
用来设置线程是否成为守护线程,即守护用户线程,当最后一个用户线程结束时,所有守护线程自动结束。
Runnable
- 通过创建任务分配给多线程执行来实现多线程,更适合多个线程同时执行相同任务的情况。
- 避免单继承Thread带来的局限性。
- 任务与线程是分离的。
public class MyRunnable implements Runnable{
@Override
public void run() {
// 线程的任务
System.out.println(Thread.currentThread().getName());
}
}
public class Main {
public static void main(String[] args) throws InterruptedException {
MyRunnable r = new MyRunnable();// 创建一个任务对象
Thread t = new Thread(r,"线程1");
t.start();
}
}