4. java并发编程基础
1. 进程和线程
什么是进程:
进程是一个具有独立功能的程序在一个数据集上的一次动态执行的过程,是操作系统进行资源分配和任务调度的一个独立单位,是应用程序运行的载体。
进程具有四种特性:动态性、并发型、独立性、结构性。
什么是线程:
线程是程序执行中一个单一的顺序控制流程,是程序执行流的最小单元,是处理器调度和分派的基本单位。一个进程可以有一个或多个线程,各个线程之间共享程序的内存空间。一个标准的线程由线程ID,当前指令指针PC,寄存器和堆栈组成。而进程由内存空间(代码,数据,进程空间,打开的文件)和一个或多个线程组成。
进程和线程的区别:
- 进程是资源分配和调度的最小单位,而线程是程序执行的最小单位。
- 一个进程可以由若干个线程组成,线程是一个进程中代码的不同执行路线。
- 进程之间相互独立,而线程之间是共享程序的内存空间及一些进程级别的资源,线程对其他进程是不可见的。
- 线程的上下文切换要比进程的上下文切换快。
1. 优先级
时间片的长短决定了线程使用樗里子资源的多少
优先级的大小决定了线程多或者少获得处理器资源
优先级的范围是1~10,默认优先级是5
2. 线程状态
- new : 初始状态
- runnable:运行状态
- blocked:阻塞状态
- wait:等待状态
- time-waiting:超时等待等待
- terminated:终止状态
3. Daemon
Daemon是守护线程,一种支持型线程,主要被用作程序中后台调度、支持性工作。
如果JVM中不存在非Daemon线程时,JVM将会退出。
//通过此方法可以将线程设置成Daemon线程
Thread.setDaemon(true);
2. 线程启动和终止
1. 构建线程
- 继承Thread类重写run方法
public class ThreadTest extends Thread{
private int i = 0 ;
@Override
public void run() {
}
}
//Thread类中的初始化方法
private void init(ThreadGroup g, Runnable target, String name,
long stackSize, AccessControlContext acc,
boolean inheritThreadLocals)
- 继承Runnable接口重写run方法
public class RunnableTest implements Runnable {
private int i ;
@Override
public void run() {
}
}
-
使用Callable和Future
Callable接口可以实现返回值和抛出异常。
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.FutureTask;
class CallableT implements Callable{
@Override
public Integer call() throws Exception {
int count = 0 ;
for (int i=0 ; i<(int)(Math.random()*100) ; i++){
count += i ;
}
return count ;
}
}
public class CallableTest {
public static void main(String[] args) {
List<FutureTask<Integer>> list = new ArrayList<>() ;
for (int i = 0 ; i<10 ; i++){
FutureTask<Integer> task = new FutureTask<Integer>(new CallableT()) ;
new Thread(task).start();
list.add(task) ;
}
for (int i=0 ; i<10 ; i++){
try {
System.out.println(list.get(i).get());
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
}
}
}
}
2. 安全的终止线程
isInterrupted()方法和自定义的boolean类型标记值
3. ThreadLocal
ThreadLocal是一个线程的内部存储类,帮线程维持着Map,key就是线程,value就是存储的对象。
实际上是ThreadLocal中的静态内部类ThreadLocalMap为每个线程都维护着一个table数组,ThreadLocal确定下标,value就是对应位置的数据。
private Entry getEntry(ThreadLocal<?> key) {
int i = key.threadLocalHashCode & (table.length - 1);
Entry e = table[i];
if (e != null && e.get() == key)
return e;
else
return getEntryAfterMiss(key, i, e);
}
ThreadLocal和Synchronized
他们两个都是为了解决线程冲突问题。
ThreadLocal是通过本地备份来解决的,每个线程有独立的一份数据,牺牲了空间来解决。
Synchronized是通过线程等待来解决的,访问共享变量的时候加锁,保证只有一个线程访问到资源,牺牲时间来解决问题。
ThreadLocal更具有灵活性,隔离效果更好,但是数据的一致性和可见性保证不了。
3. 线程池技术
public interface ThreadPool<Job extends Runnable> {
/**
* 执行一个job,实现Runnable接口
* @param job
*/
void execute(Job job);
/**
* 关闭线程
*/
void shutdown() ;
/**
* 增加工作者线程
* @param num
*/
void addWorks(int num) ;
/**
* 减少工作者线程
* @param num
*/
void removeWorks(int num) ;
/**
* 得到任务的数量
* @return
*/
int getJobSize() ;
}
import java.util.ArrayList;
import java.util.Collections;
import java.util.LinkedList;
import java.util.List;
import java.util.concurrent.atomic.AtomicLong;
public class DefaultThreadPool<Job extends Runnable> implements ThreadPool<Job> {
private static final int MAX_WORK_NUMBERS = 10 ;
private static final int DEFAUT_WORKER_NUMBERS = 5 ;
private static final int MIN_WORK_NUMBERS = 1 ;
private final LinkedList<Job> jobs = new LinkedList<>() ;
private final List<Worker> workers = Collections.synchronizedList(new ArrayList<>()) ;
private int workerNum = DEFAUT_WORKER_NUMBERS ;
private AtomicLong threadNum = new AtomicLong() ;
public DefaultThreadPool(){
initializeWorkers(DEFAUT_WORKER_NUMBERS) ;
}
public DefaultThreadPool(int num){
this.workerNum = num > MAX_WORK_NUMBERS ? MAX_WORK_NUMBERS :
num < MIN_WORK_NUMBERS ? MIN_WORK_NUMBERS : num ;
initializeWorkers(this.workerNum);
}
private void initializeWorkers(int defautWorkerNumbers) {
for (int i=0 ; i<this.workerNum ; i++){
Worker worker = new Worker() ;
workers.add(worker) ;
Thread thread = new Thread(worker , "Thread-Worker-"+threadNum.incrementAndGet()) ;
thread.start() ;
}
}
@Override
public void execute(Job job) {
if (job != null){
synchronized (jobs){
jobs.addLast(job);
jobs.notifyAll();
}
}
}
@Override
public void shutdown() {
for (Worker worker : workers) {
worker.shutdown() ;
}
}
@Override
public void addWorks(int num) {
synchronized (jobs){
if (num + this.workerNum > this.MAX_WORK_NUMBERS){
num = MAX_WORK_NUMBERS - this.workerNum ;
}
initializeWorkers(num);
this.workerNum += num ;
}
}
@Override
public void removeWorks(int num) {
synchronized (jobs){
if (num >= this.workerNum){
throw new IllegalArgumentException("beyond workNum") ;
}
int count = 0 ;
while(count < num){
Worker worker = workers.get(num) ;
if (workers.remove(worker)){
worker.shutdown();
}
}
this.workerNum -= count ;
}
}
@Override
public int getJobSize() {
return this.jobs.size();
}
/**
* 工作者,负责处理消费者
*/
private class Worker implements Runnable{
private volatile boolean running = true ;
@Override
public void run() {
while (running){
Job job ;
synchronized (jobs){
while(jobs.isEmpty()){
try {
jobs.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
job = jobs.removeFirst() ;
}
if (job != null){
try{
job.run();
}catch (Exception e){
e.printStackTrace();
}
}
}
}
public void shutdown() {
this.running = false ;
}
}
}