1、实现并发最直接的方式是在操作系统级别使用进程。(通过并发提高cpu的使用率)
2、线程机制是在由执行程序表示的单一进程中创建任务(servlet具有天生的多线程性,java的多线程机制是抢占式的,通过并发提高应用程序的使用率,但是对于没有阻塞的任务意义不大)
3、Java程序的运行原理及JVM的启动是多线程的吗?
A:Java命令去启动JVM,JVM会启动一个进程,该进程会启动一个主线程。
B:JVM的启动是多线程的,因为它最低有两个线程启动了,主线程和垃圾回收线程。
多线程的实现方案(自己补齐步骤及代码 掌握)
A:继承Thread类
B:实现Runnable接口
我们可以通过调用start()方法启动线程,但是java SE5中的java.util.concurrent包中的执行器(executor)可以替我们管理thread对象。
常用的线程池有三种,各有特点,FixedThreadPool、 SingleThreadPool.CachedThreadPool
通过线程池启动线程,管理thread对象,直接执行任务。
案列
public void test1() {
ExecutorService executorService=Executors.newCachedThreadPool();
for(int i=0;i<5;i++){
executorService.execute(new LifeOff()); //这个方法来自于Executor接口。与submit功能相同
}
executorService.shutdown();//关闭线程池。
}
@Test
public void test2() {
ExecutorService executorService=Executors.newCachedThreadPool();
for(int i=0;i<5;i++){
executorService.submit(new LifeOff());
}
executorService.shutdown();
}
4、’核心方法介绍(具体详细看编程思想)
yield(),线程礼让,当前执行的线程退出run,进入到start模式。 通过Thread.yield();调用
setPriority(),getPriority(),在任何时刻通过,通过Thread。currentThread().setPriority();获得线程的优先级。
sleep(),是当前正在执行的线程休息等待多久。Thread.sleep(1000);
jion(),线程加入,当某个线程a在另一个线程b上调用b。join()方法时,那么a线程将被挂起,直到b线程运行结束。
interrupt(),中断线程,及结束线程,如果该线程加入了join(),方法,那么此时join将失效,其他线程不必等待,开始执行。
wait、notifyall,必须在同步控制块或同步控制方法里面,因为wait需要获取锁,如果没有获取到,会报错,当调用wait方法时,锁会被释放,唤醒等待线程需要在获得wait锁的控制
块中,才能做到,notify和notifyall的使用,个人感觉吗,一般都是释放notifyall吧,释放所有。可能要到实践中才能体会到两者的区别的意义。
5、并发存在的问题,解决方案
并发,必然导致共享资源冲突,,对于共享资源我们通过加锁机制解决,使代码在一段时间内只允许运行某一段代码,
java提供了synchronized锁机制,它会检查锁是否可用,可用获取锁,执行代码,释放锁。
第二种方式使用显示的lock对象,(synchronized更简单,但是特需情况下使用lock)
第三种方法使用原子
特点:上述三种方法,效率越来越高,难度越来越大,可读性越来越低,
volatile确保应用的可视性,如果将一个字段声明为volatile,那么这个字段做的任何改变,读的时候都会看到这个修改。使用volatile而不是使用synchronize是类中只有
一个可变的的域
Threadlocal线程本地存储。解决变量共享。(案列:数据库连接池不能共享)
6、
线程间的状态转换:
1. 新建(new):新创建了一个线程对象。
2. 可运行(runnable):线程对象创建后,其他线程(比如main线程)调用了该对象的start()方法。该状态的线程位于可运行线程池中,等待被线程调度选中,获取cpu 的使用权 。
3. 运行(running):可运行状态(runnable)的线程获得了cpu 时间片(timeslice) ,执行程序代码。
4. 阻塞(block):阻塞状态是指线程因为某种原因放弃了cpu 使用权,也即让出了cpu timeslice,暂时停止运行。直到线程进入可运行(runnable)状态,才有机会再次获得cpu timeslice 转到运行(running)状态。阻塞的情况分三种:
(一). 等待阻塞:运行(running)的线程执行o.wait()方法,JVM会把该线程放入等待队列(waitting queue)中。
(二). 同步阻塞:运行(running)的线程在获取对象的同步锁时,若该同步锁被别的线程占用,则JVM会把该线程放入锁池(lock pool)中。
(三). 其他阻塞:运行(running)的线程执行Thread.sleep(long ms)或t.join()方法,或者发出了I/O请求时,JVM会把该线程置为阻塞状态。当sleep()状态超时、join()等待线程终止或者超时、或者I/O处理完毕时,线程重新转入可运行(runnable)状态。
死亡(dead):线程run()、main() 方法执行结束,或者因异常退出了run()方法,则该线程结束生命周期。死亡的线程不可再次复生。
7、死锁任务之间相互等待的连续循环,没有哪个线程能够继续,这被称为死锁。
死锁的四个必要条件,
1、互斥条件,任务中使用的资源至少有一个是不能共享的
2、至少有一个任务持有一个资源,且在等待获取一个当前别的任务持有的资源,
3、资源不能被任务抢占
4、必须有循环等待。
java类库中的新构件(学习中)