java 进程和线程
进程概念:
I. 程序是静止的,进程(Process)是动态的,运行时的程序被称为进程。
II. 单核CPU在任何时间点上,只能有一个进程在运行,宏观并行,微观串行。
进程的组成
进程由进程控制块,程序段,相关数据段组成
线程概念:
I. 轻量级进程(Light Weight Process LWP),程序中的一个顺序控制流程。
II. CPU的基本调度单位。
III. 在单个进程中同时运行多个线程完成不同的工作,交替执行,称为多线程
线程的组成:
I. CPU时间片:操作系统分配时间片(5~20ms)
II. 运行数据:
1). 堆:存储对象,共享。
2). 栈:存储局部变量,独立。
JAVA线程创建:
方式1:
实现Runnable接口,覆盖run()方法。 implements Runnable
创建实现类对象。 Runnable task = new MyTask();
创建Thread对象,并接受Runnable实现类对象。 Thread t1 = new Thread(task);
启动线程。 t1.start();
Runnable runnable=new Runnable() {
@Override
public void run() {
}
};
Thread thread=new Thread(runnable);
thread.start();
方式2:
继承Thread类,覆盖run方法。 extends Thread
创建Thread对象。 Thread t2 = new MyThread();
启动线程。 t2.start();
public class Animal extends Thread{
@Override
public void run() {
System.out.println("aaaaaaaaaaaaa");
super.run();
}
}
public void test1(){
Animal animal=new Animal();
animal.start();
}
两种方法都要用到Thread类
常用方法:
1). public static void sleep(long millis); 当前线程主动休眠millis秒
2). public static void yield(); 当前线程主动放弃时间片,回到就绪状态,竞争下一次时间片
3). public final void join(); 允许其他线程加入到当前线程中
概念描述
线程同步:
形容一次方法调用,同步一旦开始,调用者必须等待该方法返回,才能继续
线程异步:
形容一次方法调用,异步一旦开始,像是一次消息传递,调用者告知之后立刻返回。
二者竞争时间片,并发执行
线程不安全:
当多线程并发访问临界资源时,如果破坏原子操作,可能造成数据不一致。
临界资源:
共享资源(同一对象),一次仅允许一个线程访问,才可保证其正确性。
原子操作:
不可分割的多步操作,被视为一个整体,其步骤和顺序不可打乱或缺省。
互斥代码
int a=1;
int b=2;
public void t1(){
if (this.a==1){
a=0;
System.out.println("2222222222222222");
if(this.b==2){
System.out.println("bbbbbbbbb");
}
}
}
public void t2(){
if (this.b==2){
b=1;
System.out.println("11111111111");
if(this.a==1){
System.out.println("aaaaaaaaaa");
}
}
}
互斥锁标记:
每个对象都有一个锁标记,用来分配给线程。
线程同步:
同步代码块:
synchronized(临界资源对象){ //对临界资源对象加锁
//代码(原子操作)
}
注:只有拥有对象锁标记的线程,才能进入对该对象加锁的同步代码块。线程退出同步代码块时,会释放相应的锁 标记。
同步方法:
访问修饰符 synchronized 返回值类型 方法名(参数列表){
//代码(原子操作)
}
注:只有拥有对象锁标记的线程,才能进入对this加锁的同步方法,线程退出同步方法时,会释放相应的锁标记。
Wait和Notify
使用时当前线程必须有对象的监视器,根据JavaDoc
为给定对象执行了同步实例方法
在给定对象上执行了synchronized块的主体。
通过为Class类型的对象执行同步静态方法
注:一次只有一个活动线程有监视器,即线程是同步的。
wait(挂起一个线程)
访问控制符为public;
修饰符为final;
返回值为空.
wait();在同步代码块中执行,线程无线等待
wait(long timeout) 在同步代码块中线程等待一定时间wait()和wait(0)相同。
wait(long time ,int nanos)
功能相同,精度更高。
通知(释放一个线程)
访问控制符为public;
修饰符为final;
返回值为空.
notify() //在同步代码块中,随机选取等待在obj队列中的线程,唤醒到就绪状态。
notifyAll() //唤醒所有
线程池:
概念:
线程容器,可设定固定数量的线程对象,将预先创建的线程对象存入池中,并重用,避免频繁创建及销毁。
Lock:
方法:
void lock() //获取锁
void unlock() //释放锁
boolean tryLock() //尝试获取锁,获取到则执行,获取不到不阻塞
实现类:
I. ReentrantLock:与Synchronized比较,性能相同,功能更强大。必须手动获取锁、释放锁。
ReentrantReadWriteLock:
支持一写多读的锁,可分别分配读锁和写锁。
1). 互斥规则:
写-写:互斥、阻塞
写-读:互斥、写阻塞读、读阻塞写
读-读:不互斥、不阻塞
方法:
readLock() //获取读锁
writeLock() //获取写锁
线程安全的集合:
Collections工具类获取线程安全集合:JDK1.2提供,接口统一、维护性高,但性能没有提升,均以synchonized实现。
public static Collection synchronizedCollection(Collection c)
public static List synchronizedList(List list)
public static Set synchronizedSet(Set s)
public static <K,V> Map<K,V> synchronizedMap(Map<K,V> m)
public static SortedSet synchronizedSortedSet(SortedSet s)
public static <K,V> SortedMap<K,V> synchronizedSortedMap(SortedMap<K,V> m)
CopyOnWriteArrayList:
线程安全的ArrayList,加强版读写分离。
写有锁,读无锁,读写之间不阻塞,优于读写锁。
写入时,先copy一个容器副本、再添加新元素,最后替换引用。
使用方式与ArrayList无异。
CopyOnWriteArraySet:
线程安全的Set,底层使用CopyOnWriteArrayList实现。
唯一不同在于,使用addIfAbsent()添加元素,会遍历数组,
如存在元素,则不添加(扔掉副本)。
ConcurrentHashMap:(JDK8 CAS实现)
初始容量默认为16段(Segment),使用分段锁设计。
不对整个Map加锁,而是为每个Segment加锁。
当多个对象存入同一个Segment时,才需要互斥。
最理想状态为16个对象分别存入16个Segment,并行数量16。
使用方式与HashMap无异。
Queue:
- 常用方法:返回特殊值
boolean offer(E e) //顺序添加一个元素(如果到达队列上限,则返回false)
E poll() //移除队列的头元素,如果队列为空,则返回null
E peek() //获取队列的头元素,如果队列为空,则返回null
实现类:
I. LinkedList:可用于调用以上Queue的方法,完成FIFO操作。
II. ConcurrentLinkedQueue:线程安全,可高效读写的队列,高并发下性能最好的队列。(无锁,CAS比较交换算法)
(V,E,N) V = 要更新的变量 , E = 预期值, N = 新值,只有当V == E时,V = N的赋值。
**BlockingQueue子接口:**阻塞的队列
方法:
void put(E e) //将e插入到队列中,如果没有空位,则无限期等到,直至有空位为止。
E take() //获取队列的头元素,如果没有可用元素,则无限期等待,直至可用为止。
实现类:
1). ArrayBlockingQueue:数组结构存储,有界队列。(手工固定上限)
2). LinkedBlockingQueue:链表结构存 储,无界队列。(默认上限2147483647)
十、AtomicInteger:可以用原子方式更新的int值。