最近面试发现,每家都或多或少的要问到多线程的问题.回来查询各种资料在这里整理一下.
一.提到多线程不得不提到进程,那么进程和线程什么关系?
1.举个例子:比如cpu是一个工厂,进程是一个车间,线程是车间里的工人,车间的空间是有限的,若只有一个卫生间且只能被一个人占用,防止同时进入,便会有一把锁;
总结有如下2个特点:
(1).一个单核 cpu,同一时间只能运行一个进程.一个进程中有多个线程,多个线程协调完成一个进程任务
(2).线程不能单独存在,当一个线程占用了该进程中的某个内存空间,其它进程只能等待.
二.时间片的概念(可以百度看一下,计算机原理知识)
先考虑个问题,单个cpu是如何实现多个进程同时运行的?
原因在于时间片的切换:时间片是有时间限制的,时间一到cpu强制切换优先级高的程序,时间片切换速度非常快,所以人感觉不到.
三.JDK中的线程:
1.实现多线程的三种方法(具体代码这里不贴)
(1).继承thread (由于类只能单继承,所以扩展性比较差),源码中可以看到,继承了Thread其实也实现了Runnable接口
(2)实现Runnable接口
(3)使用ExecutorService、Callable、Future实现有返回结果的多线程
2.多线程流程图
(1).start()方法:调用start()方法会自动调用run方法执行,且是并行(同时执行)的.
(2).sleep(时间):占用cpu资源,一直不释放等待时间到切换成运行状态.另一个睡眠状态是时间切片用完也会如此
(3).wait()与notify(notifyAll)
这里贴一下官方文档的解释
void notify()
Wakes up a single thread that is waiting on this object’s monitor.
译:唤醒在此对象监视器上等待的单个线程
void notifyAll()
Wakes up all threads that are waiting on this object’s monitor.
译:唤醒在此对象监视器上等待的所有线程
void wait( )
Causes the current thread to wait until another thread invokes the notify() method or the notifyAll( ) method for this object.
译:导致当前的线程等待,直到其他线程调用此对象的notify( ) 方法或 notifyAll( ) 方法
void wait(long timeout)
Causes the current thread to wait until either another thread invokes the notify( ) method or the notifyAll( ) method for this object, or a specified amount of time has elapsed.
译:导致当前的线程等待,直到其他线程调用此对象的notify() 方法或 notifyAll() 方法,或者指定的时间过完。
void wait(long timeout, int nanos)
Causes the current thread to wait until another thread invokes the notify( ) method or the notifyAll( ) method for this object, or some other thread interrupts the current thread, or a certain amount of real time has elapsed.
译:导致当前的线程等待,直到其他线程调用此对象的notify( ) 方法或 notifyAll( ) 方法,或者其他线程打断了当前线程,或者指定的时间过完。
1>wait()释放同步锁,必须要结合notifyAll()使用,不然运行时会报错.
2>wait()和notifyAll()不属于Thread类,属于Object基础类,多以每个对象都有.
3>在while循环里而不是if语句下使用wait,这样,会在线程暂停恢复后都检查wait的条件,并在条件实际上并未改变的情况下处理唤醒通知
4>假设有三个线程执行了obj.wait( ),那么obj.notifyAll( )则能全部唤醒tread1,thread2,thread3,但是要继续执行obj.wait()的下一条语句,必须获得obj锁,因此,tread1,thread2,thread3只有一个有机会获得锁继续执行,例如tread1,其余的需要等待thread1释放obj锁之后才能继续执行。
5>当调用obj.notify/notifyAll后,调用线程依旧持有obj锁,因此,thread1,thread2,thread3虽被唤醒,但是仍无法获得obj锁。直到调用线程退出synchronized块,释放obj锁后,thread1,thread2,thread3中的一个才有机会获得锁继续执行
3 synchronized静态同步方法与非静态同步方法
1>所有的非静态同步方法用的都是同一把锁——实例对象本身
2>而所有的静态同步方法用的也是同一把锁——类对象本身
3.多线程的应用举例:多个页面打开同一个网站的某个功能页面,服务器会为每一个请求开辟一个线程,即多线程.
4.多线程和并发的关系:多线程执行效率就是评判并发效果的好坏,案例.前台页面访问服务器,如果数据库优化的好返回时间大大减少
四.总结
1、线程同步的目的是为了保护多个线程访问一个资源时对资源的破坏。
2、线程同步方法是通过锁来实现,每个对象都有切仅有一个锁,这个锁与一个特定的对象关联,线程一旦获取了对象锁,其他访问该对象的线程就无法再访问该对象的其他同步方法。
3、对于静态同步方法,锁是针对这个类的,锁对象是该类的Class对象。静态和非静态方法的锁互不干预。一个线程获得锁,当在一个同步方法中访问另外对象上的同步方法时,会获取这两个对象锁。
4、对于同步,要时刻清醒在哪个对象上同步,这是关键。
5、编写线程安全的类,需要时刻注意对多个线程竞争访问资源的逻辑和安全做出正确的判断,对“原子”操作做出分析,并保证原子操作期间别的线程无法访问竞争资源。
6、当多个线程等待一个对象锁时,没有获取到锁的线程将发生阻塞。
7、死锁是线程间相互等待锁锁造成的,在实际中发生的概率非常的小。真让你写个死锁程序,不一定好使,呵呵。但是,一旦程序发生死锁,程序将死掉。
8、如何解决web开发中多线程抢夺同一资源的问题:用synchronized修饰方法或代码块,能保证同一时刻最多只有一个线程执行该代码.
9、spring是如何解决线程并发问题:spring使用ThreadLocal解决线程安全问题.