关于多线程的基础问题
线程和进程的区别
进程是计算机资源分配的基本单位,线程是CPU调度的基本单位,一个进程中包含了多个线程来完成不同的任务。不同的进程会使用不同的内存空间,在同一个进程中的所有线程可以共享内存空间。线程相对来说更轻量化,线程的上下文切换要比进程的切换效率高。
并发与并行的区别
并发是计算机在同一时间应对多个事情,线程轮流使用CPU。
并行是计算机在同一时间做多个事情,多个线程同时使用CPU。
创建线程的方式
- 继承Thread类创建线程
- 实现Runnable接口创建线程
- 实现Callable接口创建线程
- 线程池创建线程
runnable和callable的区别
Runnable接口中run()方法没有返回值,而Callable接口中call()方法有返回值,是泛型,和Future、FutureTask配合使用可以实现异步调用。
同时Callable接口的call()方法允许抛出异常,而Runnable的run()方法的异常只能内部解决。run()和start()的区别
start()用来启动线程,通过该线程调用run方法执行run方法中定义的代码,start()方法只能被调用一次
run()封装了要被线程执行的代码,可调用多次。
线程状态
线程主要有六种状态,分别为NEW, RUNNABLE, BLOCKED, WAITING, TIMED_WAITING, TERMINATED。
- NEW:线程刚被创建,尚未启动。
- RUNNABLE:线程正在执行。
- BLOCKED:线程被阻塞,A线程执行时加锁,B线程就是阻塞状态,需要等A线程执行完毕后才能执行B线程。
- WAITING:线程在等待另一个线程执行特定操作。
- TIMED_WAITING:线程在等待另一个线程执行特定操作,但是有一个时间限制。
- TERMINATED:线程已经执行完毕。
线程状态转化
首先创建线程(新建),调用start()方法变成可执行状态,执行完毕后是终止状态。
在可执行状态中如果另一个线程加锁则进入阻塞状态,该线程获得锁之后才可执行。
如果线程调用了wait()方法则进入等待状态,需其他线程调用notify()方法通知后才能继续执行。
如果线程调用了sleep()方法则进入时间等待状态,经过一段时间后自动转化为RUNNABLE状态。
如何保证多线程之间的执行顺序
调用join()方法,假设有t1,t2,t3三个线程。如果我们想让线程按123的顺序走,则我们可以在创建t2线程时使用t1.join()方法,在创建t3线程时使用t2.join()方法,这样就保证了只有t1执行完毕后才会执行t2,t2执行完毕后才会执行t3。
notify()和notifyAll()的区别
notify()方法只唤醒一个随机线程
notifyAll()方法唤醒所有等待该对象的线程。
wait()和sleep()的区别
相同点:wait()和sleep()都可以让线程暂停执行一段时间,进入阻塞状态
不同点:
1.sleep()方法时Thread类中的静态方法,而wait()方法时Object类中的成员方法,每个对象都可以调用。
2.sleep(long)和wait(long) 方法中只要()中规定了参数,则会在相应的时间醒来。如果只是wait()方法则会一直沉睡,直到使用notify()方法唤醒
3.wait必须要先获取wait对象的锁才可以调用,而sleep无限制。wait方法执行后会释放对象锁,允许其他线程获取锁。sleep如果在synchronized代码块中执行,则不会释放锁。
打断运行时的线程
1.使用退出标志,可以定义一个bollean类型的变量,用来判断线程是否需要退出。
2.使用stop强制停止,不推荐
3.使用interrupt()方法中断线程。可以打断正常运行的线程,也可以打断处于wait,sleep,join状态的线程,会抛出InterruptedException异常。






