Java多线程
1. 多线程
(1) 多线程:一个应用程序有多条执行路径
进程:正在执行的应用程序
线程:进程的执行单元,执行路径。线程指在程序执行过程中,能够执行程序代码的一个执行单位,每个程序至少都有一个线程,也就是程序本身。
单线程:一个应用程序只有一条执行路径
多线程:一个应用程序有多条执行路径
多进程的意义?
提高CPU的使用率
多线程的意义?
提高应用程序的使用率
(2) Java程序的运行原理及JVM的启动是多线程的吗?
A:Java命令去启动JVM,JVM会启动一个进程,该进程会启动一个主线程。
B:JVM的启动是多线程的,因为它最低有两个线程启动了,主线程和垃圾回收线程。
C:启动一个线程是run()还是start()?它们的区别?
start();
run():封装了被线程执行的代码,直接调用仅仅是普通方法的调用
start():启动线程,并由JVM自动调用run()方法
(3) 多线程的实现方案
A:继承Thread类
B:实现Runnable接口
C:应用程序可以使用Executor框架来创建线程池
实现Runnable接口这种方式更受欢迎,因为这不需要继承Thread类。
在应用设计中已经继承了别的对象的情况下,这需要多继承(而Java不支持多继承),只能实现接口。同时,线程池也是非常高效的,很容易实现和使用。
(4) 线程的调度和优先级问题
A:线程的调度
a:分时调度
b:抢占式调度 (Java采用的是该调度方式)
B:获取和设置线程优先级
a:默认是5
b:范围是1-10
(5) 线程的控制
A:休眠线程
B:加入线程
C:礼让线程
D:后台线程
E:终止线程
(6) 线程的生命周期
A:新建:创建线程对象
B:就绪:有执行资格,没有执行权
C:运行:有执行资格,有执行权
D:阻塞:由于一些操作让线程处于了该状态,没有执行资格,没有执行权。而另一些操作却可以把它给激活,激活后就处于就绪状态。
E:死亡:线程对象变成垃圾,等待被回收
(7) 多线程安全问题的原因(也是我们以后判断一个程序是否有线程安全问题的依据)
A:是否有多线程环境
B:是否有共享数据
C:是否有多条语句操作共享数据
(8) 同步解决线程安全问题
A:同步代码块
synchronized(对象) {
需要被同步的代码;
}
这里的锁对象可以是任意对象(细粒度锁)
B:同步方法
把同步加在方法上。
这里的锁对象是this(粗粒度锁)
C:静态同步方法
把同步加在方法上。
这里的锁对象是当前类的字节码文件对象(反射再讲字节码文件对象)
(9) 回顾以前的线程安全的类
A:StringBuffer
B:Vector
C:Hashtable
D:如何把一个线程不安全的集合类变成一个线程安全的集合类
用Collections工具类的方法即可。
(10) 死锁(deadlock)
两个进程都在等待对方执行完毕才能继续往下执行的时候就发生了死锁。结果就是两个进程都陷入了无限的等待中。
public class DieLockDemo { public static void main(String[] args) { DieLock dl1 = new DieLock(true); DieLock dl2 = new DieLock(false); dl1.start(); dl2.start(); } } /*理想状态下dl1线程为true从if执行先打出"if objA"然后再接着打出"if objB"之后释放A、B的锁对象,之后dl2线程执行else语句打出"else objB","else objA"。 非理想状态下dl1先打出"if objA",之后线程dl2执行打出"else objB",然后1、2线程的锁对象A和B都处于被锁的状态,两个线程争夺锁对象发生死锁现象。*/ public class DieLock extends Thread { private boolean flag; public DieLock(boolean flag) { this.flag = flag; } @Override public void run() { if (flag) { synchronized (MyLock.objA) { System.out.println("if objA"); synchronized (MyLock.objB) { System.out.println("if objB"); } } } else { synchronized (MyLock.objB) { System.out.println("else objB"); synchronized (MyLock.objA) { System.out.println("else objA"); } } } } }
(10) 如何确保N个线程可以访问N个资源同时又不导致死锁?
使用多线程的时候,一种非常简单的避免死锁的方式就是:指定获取锁的顺序,并强制线程按照指定的顺序获取锁。因此,如果所有的线程都是以同样的顺序加锁和释放锁,就不会出现死锁了。
(11) sleep() 和 wait() 有什么区别?
sleep是线程类(Thread)的方法,导致此线程暂停执行指定时间,给执行机会给其他线程,但是监控状态依然保持,到时后会自动恢复。调用sleep不会释放对象锁。
wait是Object类的方法,对此对象调用wait方法导致本线程放弃对象锁,进入等待此对象的等待锁定池。
只有针对此对象发出notify方法(或not ifyAll)后本线程才进入对象锁定池准备获得对象锁进入运行状态。
(12) 同步和异步有何异同,在什么情况下分别使用他们?举例说明。
如果数据将在线程间共享。例如正在写的数据以后可能被另一个线程读到,或者正在读的数据可能已经被另一个线程写过了,那么这些数据就是共享数据,必须进行同步存取。
当应用程序在对象上调用了一个需要花费很长时间来执行的方法,并且不希望让程序等待方法的返回时,就应该使用异步编程,在很多情况下采用异步途径往往更有效率。
(13) 当一个线程进入一个对象的一个synchronized方法后,其它线程是否可进入此对象的其它方法?
不能,当一个线程进入一个对象的synchronized方法后,其他线程可以进入此对象的非synchronized方法,
不能进入synchronized方法,都是同一锁(同步代码块时对象锁可以是任何对象,同步方法时对象锁只能是this对象所以无法访问其他方法)
(14) 简述synchronized和java.util.concurrent.locks.Lock的异同?
主要相同点:Lock能完成synchronized所实现的所有功能。
主要不同点:Lock有比synchronized更精确的线程语义和更好的性能。
Lock是一个类,synchronized是一个关键字。synchronized会自动释放锁,而Lock一定要求程序员手工释放,并且必须在finally从句中释放。
(15) 为什么wait(),notify(),notifyAll()等方法都定义在Object类中?
因为这些方法的调用是依赖于锁对象的,而同步代码块的锁对象是任意锁。
而Object代码任意的对象,所以,定义在这里面。
2. 线程间通信的几种方式
要短信线程间通信的模型有两种:共享内存和消息传递
问题:有两个线程A、B,A线程向一个集合里面依次添加元素"abc"字符串,一共添加十次,当添加到第五次的时候,希望B线程能够收到A线程的通知,然后B线程执行相关的业务操作。
线程:进程的执行单元,执行路径。线程指在程序执行过程中,能够执行程序代码的一个执行单位,每个程序至少都有一个线程,也就是程序本身。
单线程:一个应用程序只有一条执行路径
多线程:一个应用程序有多条执行路径
3. 设计4个线程,其中两个线程每次对j增加1,另外两个线程对j每次减少1
要短信线程间通信的模型有两种:共享内存和消息传递
public class ThreadTest1 { private int j; public static void main(String args[]){ ThreadTest1 tt=new ThreadTest1(); Inc inc=tt.new Inc(); Dec dec=tt.new Dec(); for(int i=0;i<2;i++){ Thread t=new Thread(inc); t.start(); t=new Thread(dec); t.start(); } } private synchronized void inc(){ j++; System.out.println(Thread.currentThread().getName()+"-inc:"+j); } private synchronized void dec(){ j--; System.out.println(Thread.currentThread().getName()+"-dec:"+j); } class Inc implements Runnable{ public void run(){ for(int i=0;i<100;i++){ inc(); } } } class Dec implements Runnable{ public void run(){ for(int i=0;i<100;i++){ dec(); } }

浙公网安备 33010602011771号