Java多线程面试基础

LZ这几天看到一些Java初级工程师就像我们应届毕业生在去面试的时候都会或多或少问到多线程的概念,确实,这部分的内容对一个搞开发的十分的重要,掌握了就是你的优势。LZ将部分重点内容总结一下,以便和大家共享以及方便自己以后查看。

进程、线程以及它们的关系

如下图所示,进程是一个独立的运行环境,可以被称作一个程序或者一个应用,而线程就是在进程中的一个任务,即一个执行路劲,像我们平时打开电脑的任务管理器,里面看到的都是正在运行的进程,QQ是其中的一个,而我们在QQ中聊天发表说说则是一个个的线程。
进程和线程的关系图图1:进程和线程的关系图

什么是多线程

在一个应用程序中,同时有多个不同的执行路径,这就是多线程,举个例子就是在用微信聊天的时候还去对微信其他部分的东西进行操作。

多线程的优势

一句话:提高了程序的运行效率。

线程同步和异步

这个问题很好理解,要点就是在线程执行某个请求时,是否需要一段时间返回信息才能继续往下执行,同步是需要的,异步不需要,它是直接执行厦门的操作,不管其他进程的状态。如下图:
同步异步

如何创建线程

创建线程基础的有两种方法,一种是继承Thread类,重写run方法;一种是继承Runnable接口,重写run方法;注意启动一个线程用.start方法,这里需要注意的是与run方法的区别,调用run方法只是正常的调用普通的方法,而.start方法才是启动一个线程;另外考官可能会问你这两种方式那种比较好,回答应该是后者实现接口比较好,原因是实现接口的方式还可以继承其他类,但是我们的类却只能继承一个父类(Java类只能继承一个父类),所以前者会产生局限性。

方法1:继承Thread类,重写run方法

class DemoThread {

    public static void main(String[] args) {
        // TODO Auto-generated method stub
        ThreadTest2 aa = new ThreadTest2();
        aa.start(); //用于启动线程,并自动执行run方法。
    }

}
/*
 * 创建线程第一种方法:继承Thread类,重写run方法
 * */
class ThreadTest2 extends Thread{

    @Override
    public void run() {
        // TODO Auto-generated method stub
        for(int i=0;i<10;i++){
            System.out.println("i:"+i);
        }
    }
}

方法2:实现Runnable接口,重写run方法

public class DemoThread2 {

    public static void main(String[] args) {
        // TODO Auto-generated method stub
        ThreadTest3 bb = new ThreadTest3();
        Thread t1=new Thread(bb); 
        t1.start();
    }
}
/*
 * 创建线程第2种方法:实现Runnable接口,重写run方法
 * */
class ThreadTest3 implements Runnable{

    @Override
    public void run() {
        // TODO Auto-generated method stub
        for(int i=0;i<10;i++){
            System.out.println("run-i:"+i);
        }
    }
}

如果我们将上面的例子稍作修改,就能体会到多线程的存在,比如我们让主线程休眠1秒,执行情况如下:

public class ThreadTest {

    public static void main(String[] args) {
        // TODO Auto-generated method stub
        ThreadTest1 thread = new ThreadTest1();
        thread.start(); //用于启动线程,并自动执行run方法。
        thread.run();   //只是单纯的对象调用,在主线程中执行,并不开启子线程
        try {
            thread.sleep(1000); //线程休眠1秒
        } catch (InterruptedException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }

}
/*
 * 创建线程第一种方法:继承Thread类,重写run方法
 * */
class ThreadTest1 extends Thread{

    @Override
    public void run() {
        // TODO Auto-generated method stub
        for(int i=0;i<10;i++){
             System.out.println("thread run-----"+i);  
        }
    }
}

输出的结果为:

thread run-----0
thread run-----0
thread run-----1
thread run-----1
thread run-----2
thread run-----2
thread run-----3
thread run-----3
thread run-----4
thread run-----4
thread run-----5
thread run-----5
thread run-----6
thread run-----6
thread run-----7
thread run-----7
thread run-----8
thread run-----8
thread run-----9
thread run-----9

当主线程在执行休眠的时候,ThreadTest1 线程仍在执行,所以结果就会不确定,进而出现上面输出的情况。

什么是线程不安全?怎么去解决

就是在多个线程共享同一个数据会受到其他线程的干扰,可能会造成死锁,程序处于无限等待中。解决办法是采取线程同步技术,用上锁(synchronized),让一个线程执行完了,再让其他线程执行。上面提到死锁概念,觉得有必要提一下:

死锁

就是两个或两个以上的线程都在等待对方执行完毕才能继续往下执行就发生了死锁,线程处于无限的等待中。
死锁有四个条件:
禁止抢占 no preemption
持有和等待 hold and wait
互斥 mutual exclusion
循环等待 circular waiting
线程死锁
当线程A要去读取B线程已经删除的数据的时候,就会出现错误。解决死锁有几个方法,最简单的方法:重启系统,更好的方法是终止一个线程的运行,可以把一个线程或多个线程回滚到前一状态。
未完待续…
(后面会补充线程池,生产者消费者模式等知识,都是基础需要掌握的内容。)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值