1.线程和进程有什么区别?
答:
进程:是执行中一段程序,即一旦程序被载入到内存中并准备执行,它就是一个进程。进程是表示资源分配的的基本概念,又是调度运行的基本单位,是系统中的并发执行的单位。
线程:单个进程中执行中每个任务就是一个线程。线程是进程中执行运算的最小单位。
一个线程只能属于一个进程,但是一个进程可以拥有多个线程。多线程处理就是允许一个进程中在同一时刻执行多个任务。
2.如何在Java中实现线程?
答:
创建线程有两种方式:
一、继承 Thread 类,扩展线程。
二、实现 Runnable 接口。
3.多线程sleep和wait的一些区别
相同点:
二者都可以让线程处于冻结状态。
不同点:
首先应该明确sleep方法是Thread类中定义的方法,而wait方法是Object类中定义的方法。
1,sleep方法必须人为地为其指定时间。 wait方法既可以指定时间,也可以不指定时间。
2,sleep方法时间到,线程处于临时阻塞状态或者运行状态。 wait方法如果没有被设置时间,就必须要通过notify或者notifyAll来唤醒。
3.最大的不同是在等待时wait会释放锁,而sleep一直持有锁。Wait通常被用于线程间交互,sleep通常被用于暂停执行。
4.线程的start和run有什么区别?
答:
start()方法:启动线程的方法;
run()方法:run方法是个普通方法,但是线程通过start方法启动后,系统会把该run()方法当成线程执行体来处理;
5.对java多线程的认识
多线程是一种机制,它允许在程序中并发的执行多个线程,且每个线程间相互独立。
其实底部就是
多线程原理
- 同一时间,CPU只能处理1条线程,只有一条线程在工作(执行)
- 多线程并发(同时)执行,其实质是CPU快速的在多线程之间不断地在切换
7.实现多线程的两种方式:
1、继承java.lang.Thread类,并且重写它的run方法,将线程的执行主体放在其中;
2、实现java.lang.Runnable接口,实现它的run方法,并将线程的执行主体放在其中;
Java 5以后创建线程还有第三种方式:实现Callable接口,该接口中的call方法可以在线程执行结束时产生一个返回值
6.线程有五大状态
1、新建状态(New):使用new操作符创建一个线程的时候,线程还没有开始执行;
2、就绪状态(Runnable):当线程调用了start方法之后,线程就进入就绪状态;处于就绪状态的线程不一定立即运行run方法,只有获取到cpu时间才可以执行run方法;
3、运行状态(running):当线程获取到了cpu运行时间之后,就进入到运行状态了,调用run方法;
4、阻塞状态(blocked):正在运行的线程还没有结束,暂时让出cpu,这时其他就绪线程就有机会获得cpu时间;
以下原因会导致线程进入阻塞状态:
1、线程调用sleep方法进入睡眠状态;
2、线程在调用一个在i/o上被阻塞的操作
3、线程试图去获得一个锁,但是这个锁被其他线程持有;
。。。。。。
5、死亡状态(Dead):
有以下的原因可导致线程死亡:
1、run方法正常退出而正常死亡;
2、一个未捕获的异常导致线程意外退出而死亡;
可以用isAlive方法来判断线程是否还活着,只要是线程处于运行或者阻塞状态,就返回true;如果线程状态是New且不是可运行的状态或者线程死亡了,则返回false;
7.线程间的通信方式
①同步
这里讲的同步是指多个线程通过synchronized关键字这种方式来实现线程间的通信。
比如:线程B需要等待线程A执行完了methodA()方法之后,它才能执行methodB()方法。这样,线程A和线程B就实现了 通信。
②wait/notify机制
当条件未满足时(list.size() !=5),线程A调用wait() 放弃CPU,并进入阻塞状态。
当条件满足时,线程B调用 notify()通知 线程A,所谓通知线程A,就是唤醒线程A,并让它进入可运行状态。
③管道通信
8.线程间的死锁
1.什么是死锁?
死锁是指多个线程因竞争资源而造成他们互相等待,如果没有外力作用,这些进程都将无法向前推进。
比如说有两把锁,锁1和锁2,当线程1获取锁1之后,线程2也获取了锁2,这时线程1又开始获取锁2,线程2又想获取锁1,这种情况下线程1会等着线程2释放锁2,线程2会等着线程1释放锁1,然后这样就形成了死锁。
具体代码:
public class deadLock implements Runnable{
//1.创建俩把锁
public static final Object object1=new Object();
public static final Object object2=new Object();
boolean boo;
@Override
public void run() {
if(boo) {
synchronized (object1) {
System.out.println("进入1锁");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
synchronized (object2) {
System.out.println("进入2锁");
}
}
}else {
synchronized(object2) {
System.out.println("进入2锁");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
synchronized (object1) {
System.out.println("进入1锁");
}
}
}
}
}
测试代码:
public static void main(String[] args) {
deadLock d1=new deadLock();
deadLock d2=new deadLock();
d1.boo=true;
d2.boo=false;
Thread t1=new Thread(d1);
Thread t2=new Thread(d2);
t1.start();
t2.start();
}
2.如何避免死锁?
1.按顺序加锁
2.设置锁释放时间(可以使用Lock来实现)
方式一具体代码
public class openLock implements Runnable{
public static final Object object=new Object();
public static final Object object1=new Object();
boolean bool;
@Override
public void run() {
if(bool) {
synchronized (object) {
System.out.println("进入1锁");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
synchronized (object1) {
System.out.println("进入二锁");
}
}
}else {
synchronized (object) {
System.out.println("进入1锁");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
synchronized (object1) {
System.out.println("进入2锁");
}
}
}
}
}
对比死锁的代码来看,其实就是让所有的线程获取所得顺序是一样的,这样子的话就不会存在什么线程死锁的情况出现。
方式二具体代码
public class text2 {
public static void main(String[] args) {
OpenLock d1=new OpenLock();
OpenLock d2=new OpenLock();
d1.bool=true;
d2.bool=false;
Thread t1=new Thread(d1);
Thread t2=new Thread(d2);
t1.start();
t2.start();
}
}
class OpenLock implements Runnable{
//第二种解决死锁的方式是:给锁设置一个时间,如果超过这个时间的或就放弃获取这个锁。
Lock l1=new ReentrantLock();//锁1
Lock l2=new ReentrantLock(); //锁2
boolean bool;
@Override
public void run() {
if(bool) {
try {
l1.lock();
System.out.println("加上锁1");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("现在我在等待进入锁二了");
if(l2.tryLock(200, TimeUnit.MILLISECONDS)){//注意在判断这一步就已经加上锁了
try {
System.out.println("进入锁二");
}finally {
l2.unlock();
}
}else{
System.out.println("锁二一直被占用,算了我不进去了");
}
} catch (InterruptedException e) {
e.printStackTrace();
}finally {
l1.unlock();
}
}else {
l2.lock();
try {
System.out.println("进入锁二");
Thread.sleep(1000);
System.out.println("现在我在等待进入锁1了");
if(l1.tryLock(200,TimeUnit.MILLISECONDS)) {
try {
System.out.println("进入锁一");
}finally {
l1.unlock();
}
}else {
System.out.println("等带时间太长了,我不等了。");
}
} catch (InterruptedException e) {
e.printStackTrace();
}finally {
}
}
}
}
9.终止线程的方法
1、当run方法执行完毕,自动终止;
2、使用stop方法,不过这个方法不推荐使用,会有意料不到的后果;
3、使用interrupt方法
10.现在有T1、T2、T3三个线程,你怎样保证T2在T1执行完后执行,T3在T2执行完后执行?
答:要保证T1、T2、T3三个线程顺序执行,可以利用Thread类的join方法。
11.说一说自己对于 synchronized 关键字的了解
synchronized关键字解决的是多个线程之间访问资源的同步性,synchronized关键字可以保证被它修饰的方法或者代码块在任意时刻只能有一个线程执行。
12.对Java内存模型的理解,以及其在并发中的应用
jvm的了解(单机版)
Java内存模型中所有变量都存储在主内存中(虚拟机内存的一部分)。每个Java线程都存在着自己的工作内存。线程对变量的读写都在工作内存中完成,无法直接操作主内存,也无法直接访问其他线程的工作内存。
没有加 sychronized 关键字:线程A会从主内存拿变量,然后拿到工作内存运行后,把新的变量传到主内存;但因为没有加锁和线程A和线程B同时运行的情况下,线程B拿到主内存的变量会是原来的变量,而不是线程A运行后得到的新变量。
解决方案:加锁 sychronized 或者lock等
(并发的情况下)当两个线程A和线程B之间要完成通信的话,要经历如下两步:
- 线程A从主内存中将共享变量读入线程A的工作内存后并进行操作,之后将数据重新写回到主内存中;
- 线程B从主存中读取最新的共享变量
PS: sychronized 关键字使得每次线程主内存变量都能够强制刷新到主存,从而对每个线程都是可见的。
(并发的情况下)当两个线程A和线程B之间要完成通信的话,要经历如下两步:
- 线程A从主内存中将共享变量读入线程A的工作内存后并进行操作,之后将数据重新写回到主内存中;
- 线程B从主存中读取最新的共享变量
PS: sychronized 关键字使得每次线程主内存变量都能够强制刷新到主存,从而对每个线程都是可见的。

169万+

被折叠的 条评论
为什么被折叠?



