什么是线程,什么是进程
进程是指操作系统之中正在运行的程序,每一个进程都会占用主机的内存资源
线程是进程当中的一个执行的流程,多个线程之间会占用进程的内存空间
java当中是如何实现线程的呢?
第一种是继承thread类
第二种是实现runnable接口,解决了java的单继承问题,还可以实现共有的资源的访问
以卖票案例来讲解两种实现方式
需求1:两个售票窗口,各卖各的100张票(继承thread类)
需求2:两个售票窗口,共卖100张票(实现runnable接口来实现)产生了并发问题
并发问题如何解决呢?
1:最常用的是使用synchronozied同步锁来解决线程并发问题
实现原理:当有一个线程进入了同步代码块之中,它就利用jvm的计数器,
将该锁对象的标记置为1,别的线程想进入的时候,发现该锁标记为1,认为
里面有人,然后就去锁池等待。等占用同步锁的线程释放锁资源之后,就利用
jvm的计数器,再次将该锁的标记置为0,这样的话呢,别的线程就可以进入了.
两种使用方式:
1:第一种最常用的是使用同步代码块的形式(方法内部),尽量的要
减少代码块当中代码的行数和逻辑,性能做到最优
2:第二种使用同步方法的形式,锁对象是该类的静态实例(this),建议不这样使用
线程的生命周期:
1:当调用线程的start方法之后呢,该线程处于可运行状态,等待cpu分配时间片,
当获得机会之后呢,就执行run方法里面的代码,线程开始运行(运行状态),当运行完毕
之后,就死亡了,然后被GC回收.但是当在运行的过程当中,调用sleep或者wait等方法之后
进入了阻塞状态,阻塞状态结束之后,又回到了可运行状态.当遇到了synchronized同步锁
该线程进入锁池等待,等待完毕之后,又回到了可运行状态.
线程之间的通信
1:需要借助于同步锁,来实现通信。同步锁的wait(让当前持有对象锁的线程等待)
和notify或者notifyALL方法。
2:以生产者和消费者为原型.
项目当中哪些地方存在并发问题
1:servlet的并发问题
servlet是单实例,多线程的,都有大量的请求并发访问的时候,
会产生线程安全问题.
如何解决呢:
1:尽量不要使用全局变量,如果一定要使用的话呢,使用线程安全的集合类
java.util.concurrent包下面的
(concurrentHashMap)map 提供了更细粒度的分段锁,满足了并发修改map的需求
,提高了程序的吞吐量和性能
关于hashMap hashTable treeMap concurrentHashMap
(copyOnWriteArrayList) list
ArrayList 的一个线程安全的变体,其中所有可变操作(add、set 等等)
都是通过对底层数组进行一次新的复制来实现的。
同步工具类 Collections.
或者使用volatile来修饰变量
2:在方法内部使用synchronzied同步代码块
其余的并发处理方案
1:使用线程池来运行线程
java.util.executors callable(Runnable task) 类
java.util.Executor execute方法 (Runnable task);接口
当执行完之后,再把线程放回线程池,然后等待下一个任务.
它是基于生产者 消费者模式的,对线程的并发进行了处理.
优点:节省了无限制创建线程的资源开销,对并发进行了处理
首先线程的应用场景
1:java中线程的实现原理以及线程的生命周期
2: 使用同步锁的机制,原理介绍(记数1(被占有,0(未占有)),以及同步锁的概念(任意对象,如果修饰在方法上,则为该Class)
3:使用volatile 修饰变量,原理大概介绍.
4: 使用线程池来运行线程
5:使用线程安全的集合类(java.util.concurrent),比如concurrentHashMap,copyOnWriteArrayList 等