1、JDK5以后的针对线程的锁定操作和释放操作
A:为了更清晰表达在哪里如何加锁及释放锁
B:Lock锁
lock():加锁
unlock():释放锁
C:ReentrantLock 是 Lock 的实现类
private Lock lock = new ReentrantLock();
lock.lock(); //加锁
... //加锁代码
lock.unlock(); //释放锁
2、死锁问题的描述和代码体现
指两个或两个以上的线程在执行过程中,因争夺资源产生的一种互相等待现象(如果出现了同步嵌套,就容易
产生死锁问题)
3、生产者和消费者多线程体现(线程间通信问题)
A:不同种类的线程间针对同一个资源的操作
代码实现:
//在外界把这个数据创建出来,通过构造方法传递给其它类
Student s = new Student();
GetThread gt = new GetThread(s);
SetThread st = new SetThread(s);
B:以学生作为资源来实现的
资源类:Student
设置数据类:SetThread(生产者)
获取数据类:GetThread(消费者)
测试类:StudentDemo
代码:
A:最基本的版本,只有一个数据。
B:改进版本,给出了不同的数据,并加入了同步机制
C:等待唤醒机制改进该程序,让数据能够实现依次的出现
wait()
notify()
notifyAll() (多生产多消费)
D:等待唤醒机制的代码优化。把数据及操作都写在了资源类中
注:这些方法调用必须通过锁对象调用,而我们刚才使用的锁对象是任意锁对象。
所以,这些方法必须定义在Object类中。
4、线程组
把多个线程组合到一起。它可以对一批线程进行分类管理,Java允许程序直接对线程组进行控制。
public final ThreadGroup getThreadGroup():返回该线程所属的线程组
ThreadGroup tg = mt.getThreadGroup();
public final String getName():返回此线程组的名称
String name1 = tg.getName();
注:默认情况下,所有线程都属于同一个组
ThreadGroup(String name):修改线程所在的组
MyRunnable my = new MyRunnable();
ThreadGroup tg2 = new ThreadGroup("newThreadGroup");
Thread t = new Thread(tg2, my, "threadName");
tg2.get...
5、线程池
程序启动一个新线程成本比较高,使用线程池可以很好的提高性能,尤其是创建大量生存期很短的线程时,
更应该考虑使用线程池。
线程池里的每一个线程代码结束后,并不会死亡,而是再次回到线程池中成为空闲状态,等待下一个对象
来使用。
在JDK5之前,我们必须手动实现自己的线程池,从JDK5开始,Java内置支持线程池。
线程池的实现:
A: 创建一个线程池对象,控制要创建几个线程对象
public static ExecutorService newFixedThreadPool(int nThreads)
B: 这种线程池可以执行
可以执行Runnable对象或者Callable对象代表的线程
做一个类实现Runnable接口
C: 调用如下方法即可
Future<?> submit(Runnable task)
Future submit(Callable task)
D: 非要结束
pool.shutdown();
代码案例:
public static void main(String[] args){
//创建一个线程池对象,控制要创建几个线程对象
ExecutorService pool = new ExecutorService.newFixedThreadPool(2);
//可以执行Runnable对象或者Callable对象代表的线程
pool.submit(new MyRunnable());
pool.submit(new MyRunnable());
//结束线程池
pool.shutdown();
}
6、多线程实现的第三种方案
实现Callable接口,与Runnable类似
代码案例--10
7、匿名内部类方式实现多线程
A:new Thread(){代码...}.start();
B:new Thread(new Runnable(){代码...}){}.start();
代码案例:
//继承Thread类来实现多线程
new Thread(){
public void run(){
...
}
}.start();
//实现Runnable接口来实现多线程
new Thread(new Runnable(){
public void run(){
...
}
}){}.start();
8、定时器
可在指定时间执行某任务,还可以重复执行
依赖Timer 和TimerTask
Timer:定时
public Timer()
public void schedule(TimerTask task, long delay)
public void schedule(TimerTask task)
public void cancel();
代码案例:
public static void main(String[] args){
//创建定时器对象
Timer t = new Timer();
//3秒后执行爆炸任务
//t.schedule(new MyTask(), 3000);
//结束任务
t.schedule(new MyTask(t), 3000);
}
class MyTask extends TimerTask(){
private Timer t;
public MyTask(){}
public MyTask(Timer t){
this.t = t;
}
public void run(){
System.out.println("beng!!!");
t.cancel();
}
}
9、多线程的面试题
A:多线程有几种实现方案,分别是哪几种?
继承Thred类
实现Runnable接口
扩展:实现Callable接口,需要和线程池结合
B:同步有几种方式,分别是什么?
两种
同步代码块
同步方法
C:启动一个线程是run()还是start()?他们的区别是?
start();
run():封装了被线程执行的代码,直接调用仅仅是普通方法调用
start():启动线程,并由JVM自动调用run()方法
D:sleep()和wait()方法的区别
sleep():必须指定时间。不释放锁
wait():可以不指定时间,也可以指定时间,释放锁。
E:为什么wait(),notify(),notifyAll()等方法定义在Object类中
因为这些方法的调用是依赖锁对象的,而同步代码块的锁对象是任意锁。
F:线程的生命周期
新建--就绪--运行--死亡
新建--就绪--运行--阻塞--就绪--运行--死亡
建议画图解释