1. 并发与并行

  并发是指某个时间段内,多任务交替处理的能力;并行是指同时处理多任务的能力,多核CPU可以实现并行任务。

  并发执行的特点:

    (1)并发程序间相互制约:程序执行结果的相互依赖以及共享资源(如处理器、缓冲区)的竞争;

    (2)并发程序的执行过程是断断续续的,程序需要记忆现场指令及执行点;

    (3)并发数设置合理且CPU拥有足够的处理能力时,并发可以提高程序的运行效率。

2. 线程与进程

  进程是系统进行资源分配和调度的基本单位,在Java中当我们启动main函数时其实就启动了一个JVM进程,main函数所在的线程就是这个进程中的一个线程,也称主线程。

  线程是进程的一个实体,是进程的一个执行路径,一个进程中至少有一个线程 ,进程中多个线程共享进程的资源。由于真正占用CPU运行的是线程,所以进程是CPU分配的基本单位。

  由上图可知,多个线程共享进程的堆和方法区资源,但是每个线程有自己的程序计数器和栈区域,用于保存程序的执行位置以及线程的局部变量。进程中的堆被进程中所有线程共享,主要存放new操作创建的对象实例。方法区也是线程共享的,用于存放JVM加载的类,常量及静态变量等信息。

3. 多线程与并发的基本概念

内存可见性:JVM中的内存空间,服务<-->进程,线程;

synchronized关键字:Java提供的原子性内置锁,同一时间只有一个线程能进行操作该关键字修饰的代码块

volatile关键字:解决共享变量的可见性问题,线程在写入变量时不会将值缓存在寄存器或者其他地方而是直接写入主内存;保证了值的可见性,不能保证操作的原子性,即适用于写入变量值不依赖变量当前值的场景。

原子性操作:进行一系列操作时要么全部执行,要么全部不执行

CAS(Compare And Swap)比较交换,循环比较,若一致则交换,否则循环直到一致再交换

指令重排:Java内存模型允许编译器和处理器对指令重排序以提高运行性能。对于无依赖性的代码在执行过程中可能会进行指令重排,导致在多线程中操作共享变量时可能会重排指令共享变量的执行顺序,造成结果异常,可使用volatile修饰变量,使此变量写之前的操作不会重排到写之后。

伪共享:CPU一级缓存或二级缓存同一行加载多个变量,在多线程并发执行时可能会产生多个变量的值同时改变,使缓存失效,需要退回到主内存中获取变量值,影响程序执行效率。可以使用@Contended注解解决伪共享问题,但是限制在Java核心类使用,若需在用户类路径下使用,需要添加JVM参数:-XX:RestrictContended,填充宽度默认为128,要自定义宽度可以设置-XX:ContendedPaddingWidth参数。

4. 线程的三种创建方式

a. 实现Runnable接口的run方法,可以继承其他类,任务无返回值

public class ThreadTest {

	//创建线程
MyThread thread = new Thread(new Runnable() {
public void run() {
System.out.println("I'm a child thread.");
}
}); thread.start(); }

b. 继承Thread类并重写run方法,不能继承其他类,任务无返回值

public static class ThreadTest {

	public static class MyThread extends Thread {

		@Override
public void run() {
System.out.println("I'm a child thread");
}
} public static void main(String[] args) {
//创建线程
MyThread thread = new MyThread(); //启动线程
thread.start();
}
} 

c. 使用FutureTask方式,可以继承其他类,也可以拿到返回结果

public static class CallerTask implements Callable<String> {

	@Override
public String call() throws Exception {
return "hello";
} public static void main(String[] args) throws InterruptedException {
//创建异步任务
FutureTask<String> futureTask = new FutureTask<>(new CallerTask()); //启动线程
new Thread(futureTask).start(); try {
//等待任务执行完毕,并返回结果
String result = futureTask.get();
System.out.println(result);
} catch (ExcutionException e) {
e.printStackTrace();
}
} }

5. 线程的五种状态

6. 线程通知与等待

  a. wait()等待:调用该方法的线程被阻塞挂起,其他线程调用了该共享对象的notify()或notifyAll()方法正常返回,若调用该线程的interrupt()方法,抛出InterruptedException异常返回
  b. notify()通知:一个线程调用共享对象的notify()方法后,会唤醒一个在该共享变量上调用wait()方法后被挂起的线程。

  c. notifyAll()广播:唤醒阻塞在该共享变量上的所有线程。

7. 线程的其他基本方法

  a. join 等待线程执行中止的方法:在线程1中使用线程2调用join方法会使线程1阻塞直到线程2执行结束后继续执行

  b. sleep 调用线程会让出指定时间的CPU执行权,此时间段内线程被阻塞挂起,持有的锁并不释放。

  c. yield 让出剩余时间片的CPU执行权,并未被阻塞,任处于就绪状态。

  d. 线程中断

    void interrupt():中断线程,线程B调用线程A的interrupt()方法设置线程A的中断标志为true,线程A并未被中断,仍继续执行,若A已被阻塞挂起则线程A会在被阻塞的地方抛出InterruptedException异常返回

    boolean isInterrupted():检测当前是否被中断

    boolean interrupted():检测当前线程是否被中断,若发现被中断,则会清除中断标志。

8.线程池

  线程池主要解决两个问题:一是当执行大量异步任务时线程池能提供较好的性能,线程池中的线程是可复用的,减少创建和销毁线程的开销;二是线程池提供了一种资源限制和管理的手段,如限制线程的个数,动态新增线程等。

  ThreadPoolExcutor:线程池提供了许多可调参数和可扩展接口,如newCachedThreadPool(线程池个数最多可达Integer.MAX_VALUE,线程自动回收),newFixedThreadPool(固定大小线程池),newSingleThreadExecutor(单个线程)。

   ScheduledThreadPoolExecutor:可以指定一定延迟时间后或者定时进行任务调度的线程池。、

  

public static ThreadPoolTest{
//命名线程工厂
static class NamedThreadFactory implements ThreadFactory {
private static final AtomicInteger poolNumber = new AtomicInteger(1);
private final ThreadGroup group;
private final AtomicInteger threadNumber = new AtomicInteger(1);
private final String namePrefix; NamedThreadFactory(String name) { SecurityManager s = System.getSecurityManager();
group = (s != null) ? s.getThreadGroup() : Thread.currentThread().getThreadGroup(); if (null == name || name.isEmpty()) {
name = "pool";
} namePrefix = name + "_" + poolNumber.getAndIncrement() + "-thread-";
} public Thread newThread(Runnable r) {
Thread t = new Thread(group, r, namePrefix + threadNumber.getAndIncrement(), 0); if (t.isDaemon) {
t.setDaemon(false);
} if (t.getPriority() != Thread.NORM_PRIORITY) {
t.setPriority(Thread.NORM_PRIORITY);
} return t;
} } //设置线程名称
static final String THREAD_SAVE_ACCEPT = "THREAD-ACCEPT";
static final String THREAD_SAVE_PROCESS = "THREAD-PROCESS"; //创建线程池
static ThreadPoolExecutor excutorAccept = new ThreadPoolExecutor(5, 5, 1,
TimeUnit.MINUTES,
new LinkedBlockingQueue<>(),
new NamedThreadFactory(POOL_ACCEPT);
);
static ThreadPoolExecutor excutorProcess = new ThreadPoolExecutor(5, 5, 1,
TimeUnit.MINUTES,
new LinkedBlockingQueue<>(),
new NamedThreadFactory(POOL_PROCESS);
); public static void main(String[] args) {
excutorAccept.execute(new Runnable(){
public void run() {
System.out.println("接受用户链接线程");
}
});
} public static void main(String[] args) {
excutorProcess.execute(new Runnable(){
public void run() {
System.out.println("处理业务线程");
}
});
} excutorAccept.shutdown();
excutorProcess.shutdown();
}

  

  

ThreadLocal

ThreadLocal是一个工具类,具体存放变量的是线程的threadLocals。threadLocals是一个ThreadLocalMap类型变量,内部是一个Entry数组,Entry内部的value用来存放通过ThreadLocal的set方法传递的值。

如果在线程池中使用ThreadLocal变量,要注意调用ThreadLocal的remove方法清理线程对ThreadLocal对象及值的引用,使JVM能够回收内存。原因:线程池默认创建的线程均为用户线程,在不主动调用shutdown方法时,用户线程会一直存在,导致用户线程一直持有ThreadLocal变量,使JVM无法进行内存回收,导致内存泄露。

Java并发与多线程的更多相关文章

  1. Java并发和多线程(一)基础知识

    1.java线程状态 Java中的线程可以处于下列状态之一: NEW: 至今尚未启动的线程处于这种状态. RUNNABLE: 正在 Java 虚拟机中执行的线程处于这种状态. BLOCKED: 受阻塞 ...

  2. Java 并发和多线程(一) Java并发性和多线程介绍[转]

    作者:Jakob Jenkov 译者:Simon-SZ  校对:方腾飞 http://tutorials.jenkov.com/java-concurrency/index.html 在过去单CPU时 ...

  3. Java并发和多线程:序

      近期,和不少公司的"大牛"聊了聊,当中非常多是关于"并发和多线程"."系统架构"."分布式"等方面内容的.不少问题, ...

  4. Java并发和多线程2:3种方式实现数组求和

    本篇演示3个数组求和的例子. 例子1:单线程例子2:多线程,同步求和(如果没有计算完成,会阻塞)例子3:多线程,异步求和(先累加已经完成的计算结果) 例子1-代码 package cn.fansuni ...

  5. Java并发与多线程教程(2)

    Java同步块 Java 同步块(synchronized block)用来标记方法或者代码块是同步的.Java同步块用来避免竞争.本文介绍以下内容: Java同步关键字(synchronzied) ...

  6. Java并发与多线程教程(1)

    Java并发性与多线程介绍 在过去单CPU时代,单任务在一个时间点只能执行单一程序.之后发展到多任务阶段,计算机能在同一时间点并行执行多任务或多进程.虽然并不是真正意义上的“同一时间点”,而是多个任务 ...

  7. java并发与多线程面试题与问题集合

    http://www.importnew.com/12773.html     https://blog.csdn.net/u011163372/article/details/73995897    ...

  8. Java并发和多线程3:线程调度和有条件取消调度

    在第1篇中"并发框架基本示例",提到了Executors和ThreadPool.其中,还有个"定时调度"的方法,Executors.newScheduledTh ...

  9. Java并发和多线程1:并发框架基本示例

    Executor框架是指java 5中引入的一系列并发库中与executor相关的一些功能类,其中包括ThreadPool,Executor,Executors,ExecutorService,Com ...

  10. Java并发和多线程(二)Executor框架

    Executor框架 1.Task?Thread? 很多人在学习多线程这部分知识的时候,容易搞混两个概念:任务(task)和线程(thread). 并发编程可以使我们的程序可以划分为多个分离的.独立运 ...

随机推荐

  1. java高级之多线程

    1.1,多线程的作用: *线程是程序执行的一条路径, 一个进程中可以包含多条线程 *多线程并发执行可以提高程序的效率, 可以同时完成多项工作 1.2,多线程的应用场景: * 红蜘蛛同时共享屏幕给多个电 ...

  2. 指定JSON.toJSONString中实体类属性的输出顺序

    最近在使用JSON.toJSONString过程中出现实体类的属性与转换之前的顺序不一致 public static void main(String[] args) { Person person ...

  3. weblogic密码重置----未做成

    1.备份DefaultAuthenticatorInit.ldift文件 [root@test4 ~]# find / -name DefaultAuthenticatorInit.ldift /ap ...

  4. 20190521 - macOS 中显示隐藏文件的快捷键

    macOS 中显示隐藏文件,以前总是借助于命令行或第三方软件,其实有一个快捷键: shift + cmmand + .

  5. python3速查参考- python基础 3 -> -> while循环实例 + Continue && break的应用 + 列表的初步学习

    while语句的应用 实例如下: """ 述求:用户登录系统,最多只能登录三次 第三次失败后,程序终止 """ user_table = { ...

  6. FUZZ测试简介

    基本思想:利用黑盒方法,发送大量恶意/随机数据到被测试系统,通过监视系统运行过程中的异常,来发现应用程序中可能存在的安全问题.

  7. 什么是阿里云ACA认证

    阿里云云计算助理工程师认证(ACA - 
Alibaba Cloud Certified Associate)是面向使用阿里云基础产品的专业技术认证,主要涉及阿里云的计算.存储.网络.安全类的核心产品 ...

  8. 第十三章 字符串 (四)之Scanner类

    一.Scanner简述 Scanner扫描器类本质上是由正则表达式实现的,可以接受任何能产生数据的数据源对象,默认以空白符进行分词(包括\n等),使用各种next方法进行扫描匹配,获取匹配的数据. 二 ...

  9. IDEA中便捷更新Git项目最新代码

    更新:IDEA中直接点击Gir后面的第一个图标 会出现一个这样的弹框,点击OK,就可以将GitLab中最新的代码更新到IDEA中(本地)

  10. 201709-3 JSON查询

    问题描述 JSON (JavaScript Object Notation) 是一种轻量级的数据交换格式,可以用来描述半结构化的数据.JSON 格式中的基本单元是值 (value),出于简化的目的本题 ...