- 进程和线程的区别
进程和线程的由来:
进程:进程独占内存空间,保存各自运行状态,相互间不干扰且可以互相切换,为并发处理任务提供了可能。
线程:共享进程的内存资源,相互间切换更快速,支持更细粒度的任务控制,使进程内的子任务得以并发执行。
进程是资源分配的最小单位,线程是CPU调度的最小单位
所有与进程相关的资源,都被记录在PCB中;进程是抢占处理机的调度单位,拥有自己的虚拟内存空间,线程只属于某个进程,并与进程内的其他线程共享进程的资源;线程只由堆栈寄存器、程序计数器和线程控制表(TCB)组成。
总结:
线程不能看作独立的应用,而进程可以看作独立的应用
进程有独立的地址空间,互不影响,线程只是进程的不同执行路径
线程没有单独的地址空间,多进程的程序比多线程程序健壮
进程的切换比线程的切换开销大
- Java进程和线程的关系:
Java对操作系统的提供的功能进行封装,包括进程和线程
运行一个程序会产生一个进程,进程至少包含一个线程
每个进程对应一个JVM实例,多个线程共享JVM里面的堆
Java采用单线程编程模型,程序会自动创建主线程
主线程可以创建子线程,原则上要后于子线程执行完成
- Thread中的start和run方法的区别
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) {
Thread t = new Thread(){
public void run(){
attack();
}
};
System.out.println("current Thread is :"+Thread.currentThread().getName());
t.run();/*结果为current main thread is :main;Fight;Current thread is:main*/
t.start();/*结果为current main thread is :main;Fight;Current thread is:Thread-0*/
}
}
调用start()方法会创建一个新的子线程并启动
run()方法只是Thread的一个普通方法的调用
- Thread和Runnable是什么关系
Thread是实现了Runnable接口的类,使得run支持多线程
因类的单一继承原则,推荐多使用Runnable接口
/*使用继承Thead类实现多线程*/
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("this is " + name + ",i=" + i);
}
}
public static void main(String[] args) {
MyThread myThread1 = new MyThread("thread1");
MyThread myThread2 = new MyThread("thread2");
MyThread myThread3 = new MyThread("thread3");
myThread1.start();
myThread2.start();
myThread3.start();
}
}
/*使用实现Runnable接口实现多线程*/
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("this is " + name + ",i=" + i);
}
}
public static void main(String[] args) {
MyRunnable myRunnable1 = new MyRunnable("runnable1");
MyRunnable myRunnable2 = new MyRunnable("runnable2");
MyRunnable myRunnable3 = new MyRunnable("runnable3");
Thread thread1 = new Thread(myRunnable1);
Thread thread2 = new Thread(myRunnable2);
Thread thread3 = new Thread(myRunnable3);
thread1.start();
thread2.start();
thread3.start();
}
}
- 如何处理线程的返回值
三种方式:
主线程等待法,即可让主线程循环等待,直到目标子线程有返回值为止;
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();
while (cw.value == null){
Thread.currentThread().sleep(100);//主线程循环等待
}
System.out.println("value:"+cw.value);
}
}
- 使用Thread类中的join()阻塞当前线程以等待子线程处理完毕,方法一思想一样;
将上述代码的主线程等待片段改为 t.join();
- 通过Callable接口实现类,然后通过FutureTask类或者是线程池获取:
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类的get()方法来获取返回值
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());
}
}
//通过线程池来处理返回值
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("task return:"+future.get());
}catch (InterruptedException e){
e.printStackTrace();
}catch (ExecutionException e){
e.printStackTrace();
}finally {
newCachedThreadPool.shutdown();
}
}
}
- 线程的状态
新建(New):创建后仍未启动的线程状态
运行(Runnable):包含Running和Ready
无限期等待(Waiting):不会被分配CPU执行时间,需要显式被唤醒;(通过调用没有设置Timeout参数的Thread.join()和Object.wait()方法,或者调用LockSupport.park()方法)
限期等待(Timed Waiting):在一定时间后被系统自动唤醒;(实现方式:Thread.sleep()方法;设置了TimeOut参数的Thread.join()和Object.wait()方法;LockSupport.parkNanos()和LockSupport.parkUntil()方法)
阻塞(Blocked):等待获取排他锁
结束(Terminated):已终止线程的状态,线程已经执行结束
(在一个终止的线程上调用start方法会抛出java.lang.IllegalThreadStateException)
- sleep()和wait()的区别
sleep()是Thread类的方法,wait()是Object类的方法
sleep()方法是在任意地方可以使用
wait()方法只能在synchronized方法或者synchronized块中使用
最主要的本质区别:Thread.sleep()只会让出CPU,不会让线程释放锁,不会导致锁行为的改变;Object.wait()不仅会让当前线程让出CPU,还会释放同步资源锁
wait()方法可以通过notify和notifyAll方法来唤醒
public class WaitSleepDemo {
public static void main(String[] args) {
final Object lock = new Object();
new Thread(new Runnable() {
@Override
public void run() {
System.out.println("thread A is waiting to get lock");
synchronized (lock){
try {
System.out.println("thread A get lock");
Thread.sleep(20);
System.out.println("thread A do wait method");
lock.wait(1000);
System.out.println("thread A is done");
}catch (InterruptedException e){
e.printStackTrace();
}
}
}
}).start();
try {
Thread.sleep(10);
}catch (InterruptedException e){
e.printStackTrace();
}
new Thread(new Runnable() {
@Override
public void run() {
System.out.println("thread B is waiting to get lock");
synchronized (lock){
try {
System.out.println("thread B get lock");
System.out.println("thread B is sleeping 10ms");
Thread.sleep(20);
System.out.println("thread B is done");
}catch (InterruptedException e){
e.printStackTrace();
}
}
}
}).start();
}
}
- notify和notifyAll的区别
notifyAll会让所有处于等待池的线程全部进入锁池去竞争获取锁的机会
notify只会随机选取一个处于等待池中的线程进入锁池去竞争获取锁的机会
- yield
当调用Thread.yieId()函数时,会给线程调度器一个当前线程愿意让出CPU使用的暗示,但是线程调度器会忽略这个暗示。
- 如何中断线程
通过调用interrupt(),通知线程应该中断了。
1、如果线程处于被阻塞状态,那么线程立刻退出被阻塞状态,并抛出一个InterruptedException异常;
2、如果线程处于正常活动状态,那么会将该线程的中断标志设置为true,被设置中断标志的线程将继续照常运行,不受影响。
所以interrupt()方法需要被调用的线程配合中断:
1、在正常运行任务时,经常检查本线程的中断标志位,如果被设置了中断标志就自行停止线程;
2、如果线程处于正常活动状态,那么会将该线程的中断标志设置为true,被设置中断标志位的线程将继续照常运行,不受影响。
public class InterruptDemo {
public static void main(String[] args) throws InterruptedException {
Runnable interruptTask = new Runnable() {
@Override
public void run() {
int i = 0;
try{
//在正常运行任务时,经常检查本线程的中断标志位,如果被设置为了中断标志位就自行停止线程
while (!Thread.currentThread().isInterrupted()){
Thread.sleep(100);
i++;
System.out.println(Thread.currentThread().getName()+"("+Thread.currentThread().getState()+")loop"+i);
}
}catch (InterruptedException e){
//在调用阻塞方法时正确处理InterruptedException异常。
System.out.println(Thread.currentThread().getName() + "(" + Thread.currentThread().getState() + ") catch InterruptedException");
}
}
};
Thread t1 = new Thread(interruptTask,"t1");
System.out.println(t1.getName()+"("+t1.getState()+") is new.");
t1.start();
System.out.println(t1.getName()+"("+t1.getState()+") is started");
//主线程休眠300ms,然后主线程给t1发中断指令
Thread.sleep(300);
t1.interrupt();
System.out.println(t1.getName()+"("+t1.getState()+") is interrupted");
//主线程休眠300ms,然后查看t1的状态
Thread.sleep(300);
System.out.println(t1.getName()+"("+t1.getState()+") is interrupted now");
}
}