一、为什么要用到并发

充分利用多核CPU的计算能力

方便进行业务拆分,提升应用性能

二、并发编程有哪些缺点

频繁的上下文切换

时间片是CPU分配给各个线程的时间,因为时间非常短,所以CPU不断通过切换线程,让我们觉得是不断执行的,时间片一般是几十毫秒。而每次切换时,需要保存当前的状态,以便能够进行回复当期状态。而这个切换是非常损耗性能,过于频繁反而无法发挥出多线程编程的优势。通常减少上下文切换可以采用无锁并发编程,CAS算法,使用最少的线程和使用协程。

比如:悲观锁就会导致频繁的上下文切换,而频繁的上下文切换可能无法发挥出多线程编程的优势

无锁并发编程

可以参照jdk1.7分段锁的思想,不同的线程处理不同的数据,这样在多线程竞争的条件下,可以减少上下文切换的时间

CAS算法

利用Atomic下使用CAS(compare and swap)算法来更新数据,使用了乐观锁,可以有效的减少一部分不必要的锁竞争带来的上下文切换。

使用最少的线程

避免创建不必要的线程,比如任务很少,但是创建了很多的线程,这样会造成大量的线程都处于等待状态。

线程安全--死锁

多线程编程中最难以把握的就是临界区线程安全问题,稍微不注意就会出现死锁的情况,一旦产生死锁就会造成系统功能不可用。

避免死锁

    • 避免一个线程同时获得多个锁
    • 避免一个线程在锁内占有多个资源,尽量保证每个所只占有一个资源
    • 尝试使用定时锁,使用lock.tryLock(TimeOut),当超时等待时当前线程不会阻塞
    • 对于数据库,加锁和解锁必须在一个数据库连接里,否则会出现解锁失败的情况

三、并行和并发

并发指的是多个任务交替执行,而并行指的是真正意义上的同时进行

实际上,如果系统内只有一个CPU,而使用多线程时,那么真实系统环境下不能并行,只能通过切换时间片的方式交替进行,而成为并发执行任务。真正的并行也只能出现在拥有多个CPU的系统中。

四、同步和异步

同步和异步通常用来形容一次方法的调用

同步方法调用一开始,调用者必须等待被调用的方法结束后,调用者后面的代码才能执行。而异步调用,指的是,调用者不管被调用方法是否完成,都会继续执行后面的代码,当被调用的方法完成后会通知调用者。

五、阻塞和非阻塞

阻塞和非阻塞常用来形容多线程间的相互影响。

比如一个线程占有了临界区资源,那么其他线程需要这个资源就必须进行等待该资源的释放,会导致等待的线程挂起,这种情况就是阻塞,而非阻塞就恰好相反,它强调没有一个线程可以阻塞其他线程,所有的线程都会尝试的往前运行

六、线程的临界区资源

临界区用来表示一种公共资源或者说共享数据,可以被多个线程使用,但是每一个线程使用时,一旦临界区资源被一个线程占有,那么其它线程必须等待。

七、新建线程有哪几种方式

一个Java线程从main()方法开始执行,然后按照既定的代码逻辑执行,看似没有其他线程参与,但是实际上Java程序天生就是一个多线程程序,包含了:

  • 分发出路发送给JVM信号的线程
  • 调用对象的finalize方法的线程
  • 清除Reference的线程
  • main线程,用户程序的入口

三种方式(有三种方式实现,JDK源码中标明只有两种方式)

1、继承Thread类,重写run方法

2、实现Runnable接口

3、实现Callable接口

public class NewThread {
/*扩展自Thread类*/
private static class UseThread extends Thread{
@Override
public void run() {
super.run();
// do my work;
System.out.println("I am extendec Thread");
}
} /*实现Runnable接口*/
private static class UseRunnable implements Runnable{ @Override
public void run() {
// do my work;
System.out.println("I am implements Runnable");
}
} public static void main(String[] args)
throws InterruptedException, ExecutionException {
UseThread useThread = new UseThread();
useThread.start();
useThread.start(); UseRunnable useRunnable = new UseRunnable();
new Thread(useRunnable).start(); }
}
public class UseFuture {

    /*实现Callable接口,允许有返回值*/
private static class UseCallable implements Callable<Integer>{
private int sum;
@Override
public Integer call() throws Exception {
for(int i= ;i<;i++){
if(Thread.currentThread().isInterrupted()) {return null;
}
sum=sum+i;
System.out.println("sum="+sum);
} return sum;
}
} public static void main(String[] args)
throws InterruptedException, ExecutionException { UseCallable useCallable = new UseCallable();
//包装
FutureTask<Integer> futureTask = new FutureTask<>(useCallable);
Random r = new Random();
new Thread(futureTask).start(); Thread.sleep();
if(r.nextInt()>){
System.out.println("Get UseCallable result = "+futureTask.get());
}else{
futureTask.cancel(true);
} } }

八、线程的转换状态

  • 线程创建之后调用start()方法开始运行,当调用wait(),join(),LockSupport.lock()方法线程会进入到WAITING状态。
  • 而同样的wait(long timeout),sleep(long time),join(),LockSupport.parkNamos(),LockSupport.parkUtil()增加了超时等待的功能,也就是调用这些方法后线程会进入TIME_WAITING状态
  • 当超时等待时间到达后线程会切换到RUNNABLE的状态,另外当WAITING和TIME_WAITING状态是可以通过notify/notifyAll方法使线程转换到RUNNABLE状态
  • 当线程出现资源竞争时,即等待获取锁的时候,线程会进入到BLOCKED阻塞状态
  • 当线程获取锁时,线程进入到RUNNABLE状态
  • 线程运行结束,线程进入到TERMINATED状态,状态转换可以说是线程的声明周期

另外需要注意的是:

当线程进入到synchronized方法或者synchronize的代码块的时候,线程切换的是BLOCKED状态,而使用lock进行加锁的时候线程切换的是WAITING或者TIME_WAITING状态,因为lock会调用LockSupport的方法

九、中断标志位--interrupted

中断可以理解为线程的一个标志位,它代表了一个运行中的线程是否被其他线程进行了中断操作。

中断好比其他线程对该线程打了一个招呼。其他线程可以调用该线程的interrupt()方法对其进行中断操作,同时该线程可以调用isInterrupted()来感知其他线程对自身的中断操作,从而做出响应。

另外,同样可以调用Thread的静态方法interrupted()对当前线程进行中断操作,该方法会清除中断标志位。

需要注意的是,当抛出interruptedExection时候,会清除中断标志位,也就是说在调用isInterrupted时会返回false。

十、join

如果一个线程实例A执行了threadB.join(),其含义是:当前线程A会等待线程threadB线程终止后threadA才会继续执行

关于join方法一共提供了如下这些方法

 public final synchronized void join(long millis)
throws InterruptedException {
long base = System.currentTimeMillis();
long now = ; if (millis < ) {
throw new IllegalArgumentException("timeout value is negative");
} if (millis == ) {
while (isAlive()) {
wait();
}
} else {
while (isAlive()) {
long delay = millis - now;
if (delay <= ) {
break;
}
wait(delay);
now = System.currentTimeMillis() - base;
}
}
} public final synchronized void join(long millis, int nanos)
throws InterruptedException { if (millis < ) {
throw new IllegalArgumentException("timeout value is negative");
} if (nanos < || nanos > ) {
throw new IllegalArgumentException(
"nanosecond timeout value out of range");
} if (nanos >= || (nanos != && millis == )) {
millis++;
} join(millis);
} public final void join() throws InterruptedException {
join();
}

Thread类出了提供join()方法外,另外还提供了超时等待的方法,如果线程threadB在等待的时间内还没有结束的话,threadA会在超时之后继续执行。join方法源码的关键是

while (isAlive()) {
wait();
}

可以看出来当前等待对象threasA会一直阻塞,知道被等待对象threadB结束后即isAlive()返回false的时候才会结束while循环,当天threadB退出时会调用notifyAll方法通知所有的等待线程。

十一、sleep和wait

  public static native void sleep(long millis) throws InterruptedException;

该方法显然是Thread的静态方法,很显然它是让当前线程按照指定的时间休眠,其休眠时间的精度取决于处理器的计时器和调度器

需要注意的是如果当前线程获得了锁,sleep方法并不会失去锁。sleep方法经常拿来和object.wait()方法进行比较,这也是面试经常被问到的地方

sleep()和wait()的区别

1.sleep方法是threa的静态方法,而wait是objectshilde方法;

2、wait方法必须要在同步方法或者同步块中调用,也就是必须获得对象锁,而sleep方法没有这个限制,可以在任何地方使用

3、wait方法会释放占有的对象锁,使线程进入到等待池中,等待下一次获取资源。而sleep方法只是会让出CPU并不会释放掉对象锁

4、sleep方法在休眠时间达到后如果再次获取CPU时间片就会继续执行,而wait方法必须等到notify/notifyAll通知后,才会离开等待池,并且再次获取CPU时间片才会继续执行

十二、yield

 public static native void yield();

1、这是一个thread的静态方法

2、一旦执行,它会是当前线程让出CPU,但是,需要注意的是,让出的CPU并不是代表当前线程不在运行了,吐过在下一次竞争中,又获得CPU时间片当前线程依旧会继续运行。另外让出的时间片智慧分配给当前相同优先级的线程

3、需注意的是sleep和yield方法,同样都是当前线程会交出处理器资源,而它们不同的是,sleep交出来的时间片其他线程都可以去竞争,也就是说都有机会获得当前线程让出的时间片。而yield方法只允许与当前具有相同优先级的线程能够获得释放出来的CPU时间片。

十三、线程的优先级

在 Java 线程中,通过一个整型成员变量 priority 来控制优先级,优先级的范围从 1~10,在线程构建的时候可以通过 setPriority(int)方法来修改优先级,默认优先级是5,优先级高的线程分配时间片的数量要多于优先级低的线程。

设置线程优先级时,针对频繁阻塞(休眠或者 I/O 操作)的线程需要设置较高优先级,而偏重计算(需要较多 CPU 时间或者偏运算)的线程则设置较低的优先级,确保处理器不会被独占。在不同的 JVM 以及操作系统上,线程规划会存在差异,有些操作系统甚至会忽略对线程优先级的设定。

十四、守护线程

Daemon(守护)线程是一种支持型线程,因为它主要被用作程序中后台调度以及支持性工作。这意味着,当一个 Java 虚拟机中不存在非 Daemon 线程的时候,Java 虚拟机将会退出。可以通过调用 Thread.setDaemon(true)将线程设置为 Daemon 线程。我们一般用不上,比如垃圾回收线程就是 Daemon 线程。

Daemon 线程被用作完成支持性工作,但是在 Java 虚拟机退出时 Daemon 线程中的 finally 块并不一定会执行。在构建 Daemon 线程时,不能依靠 finally 块中的内容来确保执行关闭或清理资源的逻辑。

Java并发--基础知识的更多相关文章

  1. java并发基础知识

    这几天全国都是关键时候,放假了,还是要学习啊!很久没有写博客了,最近看了一本书,有关于java并发编程的,书名叫做“java并发编程之美”,讲的很有意思,这里就做一个笔记吧! 有需要openjdk8源 ...

  2. Java 并发基础知识

    一.什么是线程和进程? 进程: 是程序的一次执行过程,是系统运行程序的基本单元(就比如打开某个应用,就是开启了一个进程),因此进程是动态的.系统运行一个程序即是一个程序从创建.运行到消亡的过程. 在 ...

  3. Java并发基础知识你知道多少?

    并发 https://blog.csdn.net/justloveyou_/article/details/53672005 并发的三个特性是什么? 什么是指令重排序? 单线程的指令重排序靠什么保证正 ...

  4. 目录-java并发基础知识

    ====================== 1.volatile原理 2.ThreadLocal的实现原理(源码级) 3.线程池模型以及核心参数 4.HashMap的实现以及jdk8的改进(源码级) ...

  5. java并发基础及原理

    java并发基础知识导图   一 java线程用法 1.1 线程使用方式 1.1.1 继承Thread类 继承Thread类的方式,无返回值,且由于java不支持多继承,继承Thread类后,无法再继 ...

  6. Java笔记(十四) 并发基础知识

    并发基础知识 一.线程的基本概念 线程表示一条单独的执行流,它有自己的程序计数器,有自己的栈. 1.创建线程 1)继承Thread Java中java.lang.Thread这个类表示线程,一个类可以 ...

  7. Java 多线程——基础知识

    java 多线程 目录: Java 多线程——基础知识 Java 多线程 —— synchronized关键字 java 多线程——一个定时调度的例子 java 多线程——quartz 定时调度的例子 ...

  8. Java并发基础:进程和线程之由来

    转载自:http://www.cnblogs.com/dolphin0520/p/3910667.html 在前面,已经介绍了Java的基础知识,现在我们来讨论一点稍微难一点的问题:Java并发编程. ...

  9. 什么才是java的基础知识?

    近日里,很多人邀请我回答各种j2ee开发的初级问题,我无一都强调java初学者要先扎实自己的基础知识,那什么才是java的基础知识?又怎么样才算掌握了java的基础知识呢?这个问题还真值得仔细思考. ...

随机推荐

  1. Video 自动播放

    先说ios ios之前的政策是视频只能在用户主动操作后才能播放,且播放时必须全屏. 随着 iOS 10 的正式发布,Safari 也迎来了大量更新,首先划出重点:1)iOS 10 Safari 支持特 ...

  2. MySQL数据库使用报错ERROR 1820 (HY000): You must reset your password using ALTER USER statement before executing this statement.

    今天MySQL数据库,在使用的过程中一直报错ERROR 1820 (HY000): You must reset your password using ALTER USER statement be ...

  3. 关于python爬取异步ajax数据的一些见解

    我们在利用python进行爬取数据的时候,一定会遇到这样的情况,在浏览器中打开能开到所有数据,但是利用requests去爬取源码得到的却是没有数据的页面框架. 出现这样情况,是因为别人网页使用了aja ...

  4. CobaltStrike上线Linux主机(CrossC2)

    一.简述 CrossC2插件是为企业和红团队人员提供的安全框架,支持 CobaltStrike 对其他平台的渗透测试(Linux / MacOS /...),支持自定义模块,并包括一些常用的渗透模块. ...

  5. Linux下显示运行时链接(运行时加载)

    目录 介绍 如何加载动态库 dlopen() 第一个参数: 被加载动态库的路径 第二个参数: flag表示函数符号的解析方式 dlopen 返回值 dlsym() 参数: 返回值 符号优先级 dler ...

  6. Ethical Hacking - NETWORK PENETRATION TESTING(7)

    Gaining Access to encrypted networks Three main encryption types: 1. WEP 2.WPA 3.WPA2 WEP Cracking W ...

  7. Python Ethical Hacking - Malware Packaging(2)

    PACKAGING FOR WINDOWS FROM LINUX For best results package the program from the same OS as the target ...

  8. 虚拟DOM Vitural DOM Tree

      提起Virtual DOM,总是给人一种高深莫测的感觉,大家都知道它比DOM快.那么Virtual DOM到底是何方神圣呢?在深入理解Virtual DOM之前,先让我们回顾一下DOM. 一.什么 ...

  9. scratch编程体感游戏

    体感游戏有很多种,最常见的就是摄像头和声控了,今天我们要用scratch编写一系列的体感游戏!!!是不是很激动呢? 首先我们来编摄像头类的: No.1拳头打幽灵 挥动头就能打到幽灵了哟! 具体程序如下 ...

  10. CSS把容器中的内容限制行数,在超过行数后,在最后一行显示"..."

    <style type="text/css"> .main{ width: 400px; background-color: #3498db; display: -we ...