进程是程序的运行过程,引入进程可以使得多个程序并发执行。一个进程下可以包含多个进程,多个线程彼此之间独立,但是共享进程的资源。
ReentrantLock也可以实现同样的功能,但需要借助于Condition对象。
- condition.await()
- condition.signal()
- condition.signaAll()
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.ReentrantLock;
public class ThreadAB {
public String str = new String("");
ReentrantLock lock = new ReentrantLock();
Condition condition = lock.newCondition();
public Runnable threadA = new Runnable(){
public void run() {
// TODO Auto-generated method stub
synchronized (str){
try {
System.out.println("start wait");
str.wait();
System.out.println("end wait");
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
};
public Runnable threadB = new Runnable(){
public void run() {
// TODO Auto-generated method stub
synchronized (str){
System.out.println("start notify");
str.notify();
System.out.println("end notify");
}
}
};
public Runnable threadC = new Runnable(){
public void run() {
// TODO Auto-generated method stub
lock.lock();
try {
System.out.println("start condition.await()");
condition.await();
System.out.println("end condition.await()");
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
lock.unlock();
}
};
public Runnable threadD = new Runnable(){
public void run() {
// TODO Auto-generated method stub
lock.lock();
System.out.println("start condition.signal()");
condition.signal();
System.out.println("end condition.signal()");
lock.unlock();
}
};
}
public class Main {
public static void main(String[] args) {
// TODO Auto-generated method stub
ThreadAB th = new ThreadAB();
Thread thA = new Thread(th.threadA);
Thread thB = new Thread(th.threadB);
thA.start();
thB.start();
try {
Thread.sleep(100);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
Thread thC = new Thread(th.threadC);
Thread thD = new Thread(th.threadD);
thC.start();
thD.start();
}
}
重入锁实现的是Lock接口,可以对一个对象多次上锁。
读写锁可以保证只对文件的写操作加锁,而读操作可以并发执行,增大了读写效率
两个方法都需要获得A锁和B锁。一个线程执行a方法且已经获得了A锁,在等待B锁;另一个线程执行了b方法且已经获得了B锁,在等待A锁。这种状态,就是发生了静态的锁顺序死锁。
死锁产生的条件:
为了更方便的管理线程资源,减少线程重建销毁的次数,引入了线程池的概念,线程池可以管理多个线程,设置核心线程数量,总线程数量,当有任务需要处理时,优先使用核心线程处理,核心线程已满时,进入排队序列等待,当排队序列已满并且未达到最大线程数,则采用普通线程处理。如果已经达到最大线程数,返回异常结果。
线程池构造方法参数:
- 核心线程数量
- 最大线程数量
- 超时时长
- 阻塞队列
- 拒绝策略
四种线程池类
- newFixedThreadPool,该线程池是一种线程数量固定的线程池,在这个线程池中 所容纳最大的线程数就是我们设置的核心线程数。 如果线程池的线程处于空闲状态的话,它们并不会被回收,除非是这个线程池被关闭。如果所有的线程都处于活动状态的话,新任务就会处于等待状态,直到有线程空闲出来。
public static ExecutorService newFixedThreadPool(int nThreads) {
return new ThreadPoolExecutor(nThreads, nThreads,
0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue());
}
public static ExecutorService newCachedThreadPool() {
return new ThreadPoolExecutor(0, Integer.MAX_VALUE,
60L, TimeUnit.SECONDS,
new SynchronousQueue());
}
public ScheduledThreadPoolExecutor(int corePoolSize) {
super(corePoolSize, Integer.MAX_VALUE, 0, NANOSECONDS,
new DelayedWorkQueue());
}
public static ExecutorService newSingleThreadExecutor() {
return new FinalizableDelegatedExecutorService
(new ThreadPoolExecutor(1, 1,
0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue()));
}
Java的内存中各个线程之间相互独立,每个线程都对应一个缓存空间,他们共享一块主内存,当其中一个线程修改共享变量时,首先修改缓存中的变量,之后将修改后的变量刷新到主内存。
Java并发中经常遇到的三个问题,原子性、顺序性、可见性。
volatile具有可见性和顺序性,但不具有原子性。
CAS操作包含三个操作数,内存位置(V)、预期原值(A)和新值(B)。执行CAS操作的时候,将内存位置的值与预期原值比较,如果相匹配,那么处理器会自动将该位置值更新为新值。否则,处理器不做任何操作。