并发编程基础

1.并发的发展历史

真空管和穿孔打卡

操作员在机房里来回调度资源,以及计算机同一时刻只能运行一个程序,在程序输入的过程中计算机处于空闲状态。而当时计算机是非常昂贵的,人们为了减少这种资源浪费。就采用了批处理系统来解决

晶体管和批处理系统

批处理操作系统虽然能够解决计算机空闲问题,但是当某一个作业因为等待磁盘或者其他I/O操作暂停时,那CPU就只能阻塞直到该I/O的完成,对于CPU操作密集型的程序,I/O操作相对较少,因此浪费的时间也很少但是对于I/O操作较多的场景来说,CPU的资源是属于严重浪费的

集成电路和多道程序设计

多道程序设计的出现解决了这个问题,就是把内存分为几 个部分,每一个部分放不同的程序。当一个程序需要等待 I/O 操作完成时。那么 CPU 可以切换执行内存中的另外一 个程序。如果内存中可以同时存放足够多的程序,那 CPU 的利用率可以接近 100%。 在这个时候,引入了第一个概念- 进程, 进程的本质是一个 正在执行的程序,程序运行时系统会创建一个进程,并且 给每个进程分配独立的内存地址空间保证每个进程地址不 会相互干扰。同时,在 CPU 对进程做时间片的切换时,保 证进程切换过程中仍然要从进程切换之前运行的位置出开 始执行。所以进程通常还会包括程序计数器、堆栈指针。
有了进程以后,可以让操作系统从宏观层面实现多应用并 发。而并发的实现是通过 CPU 时间片不端切换执行的。对 于单核 CPU 来说,在任意一个时刻只会有一个进程在被 CPU 调度

线程的出现

有了进程以后,为什么还会发明线程?

  1. 在多核 CPU 中,利用多线程可以实现真正意义上的并行 执行
  2. 在一个应用进程中,会存在多个同时执行的任务,如果 其中一个任务被阻塞,将会引起不依赖该任务的任务也 被阻塞。通过对不同任务创建不同的线程去处理,可以 提升程序处理的实时性
  3. 线程可以认为是轻量级的进程,所以线程的创建、销毁 比进程更快

2.线程的应用

如何创建多线程
在Java中,有多种方式来实现多线程。继承Thread类,实现Runnable接口,使用ExcutorService,Callable,Future实现带返回结果的多线程,线程池ThreadPool
线程可以合理利用多核心CPU资源,提高程序吞吐量

继承Thread类创建线程

Thread 类本质上是实现了 Runnable 接口的一个实例,代 表一个线程的实例。启动线程的唯一方法就是通过 Thread 类的 start()实例方法。start()方法是一个 native 方法,它会 启动一个新线程,并执行 run()方法。这种方式实现多线程 很简单,通过自己的类直接 extend Thread,并复写 run() 方法,就可以启动新线程并执行自己定义的 run()方法。

public class MyThread extends Thread {
    public void run() { 
        System.out.println("MyThread.run()"); 
    }
 }
MyThread myThread1 = new MyThread(); 
MyThread myThread2 = new MyThread(); 
myThread1.start();
myThread2.start();

实现Runnable接口创建线程

如果自己的类已经 extends 另一个类,就无法直接 extends Thread,此时,可以实现一个 Runnable 接口

public class MyThread extends OtherClass implements Runnable { 
        public void run() {
            System.out.println("MyThread.run()"); 
        } 
 }

实现Callable接口通过FutureTask包装器来创建Thread线程

有的时候,我们可能需要让一步执行的线程在执行完成以 后,提供一个返回值给到当前的主线程,主线程需要依赖 这个值进行后续的逻辑处理,那么这个时候,就需要用到 带返回值的线程了。Java 中提供了这样的实现方式

public class CallableDemo implements Callable { 
    public static void main(String[] args) throws ExecutionException, InterruptedException { 
        ExecutorService executorService= Executors.newFixedThreadPool(1); 
        CallableDemo callableDemo=new CallableDemo(); 
        Future future=executorService.submit(callableDemo);
        System.out.println(future.get()); 
        executorService.shutdown(); 
    } 
    @Override 
    public String call() throws Exception { 
        int a=1; int b=2; 
        System.out.println(a+b); 
        return "执行结果:"+(a+b); 
    } 
}

多线程的实际应用场景
下面举一个异步责任链的例子

Request

public class Request {
	
	private String name;
	
	@Override
	public String toString() {
		return "Request [name=" + name + "]";
	}

	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}
	
	

}

RequestProcessor

public interface RequestProcessor {
	
	void processRequest(Request request);

}

PrintProcessor

public class PrintProcessor extends Thread implements RequestProcessor {

	LinkedBlockingQueue requests = new LinkedBlockingQueue();
	
	private final RequestProcessor nextProcessor;
	
	public PrintProcessor(RequestProcessor nextProcessor){
		this.nextProcessor = nextProcessor;
	}
	
	public void run(){
		while(true){
			try {
				Request request = requests.take();
				System.out.println("printdata:"+request.getName());
				nextProcessor.processRequest(request);
			} catch (InterruptedException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}
	}
	
	@Override
	public void processRequest(Request request) {
		// TODO Auto-generated method stub
		requests.add(request);
	}

}

SaveProcessor

public class SaveProcessor extends Thread implements RequestProcessor{

	LinkedBlockingQueue requests = new LinkedBlockingQueue();
	@Override
	public void run() {
		while (true) {
			try {
				Request request=requests.take();
				System.out.println("begin save requestinfo:"+request);
			} catch (InterruptedException e) {
				 e.printStackTrace();
			}
		}
	}
	//处理请求
	public void processRequest(Request request) {
		requests.add(request);
	}

}

Main

public class Main {
	
	PrintProcessor printProcessor;
	
	protected Main(){
		SaveProcessor saveProcessor=new SaveProcessor();
		saveProcessor.start();
		printProcessor=new PrintProcessor(saveProcessor);
		printProcessor.start();
	}
	
	private void doTest(Request request){
		printProcessor.processRequest(request);
	}
	
	public static void main(String[] args) {
		Request request=new Request();
		request.setName("陈·风暴烈酒");
		new Main().doTest(request);
	}

}

Java并发编程基础

线程的生命周期
线程一共有六种状态(NEW、RUNNABLE、BLOCKED、 WAITING、TIME_WAITING、TERMINATED)
NEW:初始状态,线程被构建,但是还没有调用start方法
RUNNABLE:运行状态,Java线程把操作系统的就绪和运行两种状态统一称为“运行中”
BLOCKED:阻塞状态,表示线程进入等待状态,也就是线程因为某种原因放弃了CPU使用权阻塞也分几种情况
等待阻塞:运行的线程执行wait方法,jvm会把当前线程放入等待队列
同步阻塞:运行的线程在获取对象同步锁时,若该同步锁被其他线程锁占用了,那么jvm会把当前的线程放到锁池中
其他阻塞:运行的线程执行Thread.sleep或者t.join方法,或者发出了I/O请求时JVM会把当前线程设置为阻塞状态,当sleep结束,join线程终止,io处理完毕则线程恢复
TIME_WAITING:超时等待状态,超时以后自动返回
TERMINATED:终止状态,表示当前线程执行完毕
并发编程基础_第1张图片

你可能感兴趣的:(并发编程基础)