java并行程序基础

1 进程

	1 进程和线程之间的关系:进程是线程的容器。

2 线程


1 线程的执行流程:

  • **线程调用start()**方法时,表示线程开始执行;
  • 当线程执行时,处于RUNNABLE状态,表示线程所需的一切资源都准备好了;
  • 当线程遇到synchronized同步块,就进入BLOCED阻塞状态,这时线程会暂停执行,直到获得请求的锁。

2 WAITING 和 TIMED_WAITING:

  • WAITING 和 TIMED_WAITING都表示等待状态区别是WAITING会进入一个无时间限制的等待,TIMED_WAITING会进行一个有限的等待。
  • WAITING 的线程是在等待一些特殊事件:比如,wait()方法等待notify()方法,join等待目标线程的终止。
  • 线程的基本操作
    1 注意:不要用run()开启新线程,它只会在当前线程中,串行执行run()中的代码。
    2 创建线程的两种方式:实现Runnable接口;继承Thread类;
  //Runnable接口public interface Runable{public abstract void run();
}

4 终止线程:

  • 为何终止:一般线程会自动终止,但是一些服务端的后台线程会常驻系统,它们本身是无穷循环,用于提供某些服务。
    1 使用stop()? //未来将被废弃;
    stop()有一个局限性: 当写入两个相同的值,当线程写到一半,并强行终止,对象就会被写坏。从而出现
    写读不一致的现象。stop发生的问题很难排查!,除非你很清楚你在干什么,否则不要随便使用stop()去
    终止一个线程
    2 自行决定何时退出
    1 在自己的线程类中增加一个stopMe()方法:
ChangeObjectThread extends Thread{volatile Boolean stopme = false;public void stopMe(){stopme = true;}public void run(){while(true){if(stopme){//退出位置pringtln(“exit by stop me!”);break;}//你的代码}}
}

5 线程中断

  • 什么是线程中断:
    线程中断不会使线程立即退出,而是给线程一个通知,告知目标线程,有人希望你退出了!至于**目标线程接到通知后
    如何处理,由自己决定。**这点很重要,避免了stop()那样出现的问题。
  • 与线程中断的三种方法:
    1 Thread.interrupt():通知目标线程中断,设置中断标志
    2 Thread.isInterrupted():检查中断标志,判断当前线程是否被中断。
    3 Thread.interrupted():判断当前线程中断状态,但同时会清楚当前线程中断标志位状态
    3 如何操作:
main(String[] args){Thread t1 = new Thread(){public void run(){while(true){//中断处理程序if(Thread.currentThread().isInterrupted()){sysou("Interrupted!");break;}...;Thread.yield();//线程让步}	}}t1.start();Thread.sleep(2000);t1.interrupt();//单单这里中断是没有效果的,一定要写入上面的中断处理程序
}
  • 中断的方法比stopme()标记手法功能更强劲
  • 强劲之处:在循环体中,出现wait()或sleep(),只能通过中断识别。
    Thread.sleep()方法会抛出一个InterruptedException中断异常,当线程sleep()处于休眠时,如果被中断,异常就会产生。这时会清除中断标记位,如果不处理,在下次循环中无法捕获到这个中断,故在异常处理中,再次设置中断标记位

6 等待(wait)和通知(notify)
两个方法签名

  • 等待(wait)
    当线程A中,调用了obj.wait(),线程A停止继续执行,进入现场等待池中等待,让出系统资源,既让出了锁资源。线程A会一直等到其他线程调用obj.notify()位置。obj对象成为多个线程的有效通信手段。
  • wait 和 notify 如何工作?
    当一个线程调用obj.wait(),那么它就进入obj的等待队列。这个等待队列可能有多个线程。当obj.notify()被调用时,它会从等待队列中水机选选择一个线程,将其唤醒(这里的唤醒是允许其去获得锁)。这个选择时随机的。
  • 除了notify可以唤醒线程,还有notifyAll,只是notifyAll唤醒所有的线程,而不是一个。
  • 注意点
    object.wait()不是随便调用的,必须包含在对应同步语句中,无论是wait 还是 notify都需要首先获得目标对象
    (obj)的一个监视器。
public class SimpleWN{public static void main(String[] args) {Thread t1 = new T1();Thread t2 = new T2();t1.start();t2.start();}final static Object obj = new Object();public static class T1 extends Thread{@Overridepublic void run() {synchronized (obj) {System.out.println(System.currentTimeMillis() + ":T1 start! ");try {System.out.println(System.currentTimeMillis() + ":T1 wait for obj");obj.wait();} catch (InterruptedException e) {e.printStackTrace();}System.out.println(System.currentTimeMillis() + ":T1 end!");}super.run();}}public static class T2 extends Thread{@Overridepublic void run() {// TODO Auto-generated method stubsynchronized (obj) {System.out.println(System.currentTimeMillis() + ":T2 start! notify one thread!");obj.notify();System.out.println(System.currentTimeMillis() + ":T2 end!");try {Thread.sleep(2000);} catch (InterruptedException e) {// TODO Auto-generated catch blocke.printStackTrace();}}super.run();}}
}
  • wait 和 sleep :都是等待若干时间,区别是wait可以被唤醒,还有wait方法会释放目标对象的锁。而sleep()不会。

7 挂起(suspend)和继续执行(resume)

  • 被挂起的线程,必须等到resume()操作后,才能继续执行。
  • suspend是被废弃的方法:被挂起的线程在导致线程暂停的同时,并不会释放任何锁资源。导致其他线程想要访问被它暂用的锁资源,都会受牵连。
  • 怎样用一种可靠的方式使用suspend()?
    利用wait()和notify()方法,在应用层实现suspend 和resume 功能。
package com.sean.thread;public class GoodSuspend{public static Object u = new Object();public static void main(String[] args) throws InterruptedException {ChangeObjThread t1 = new ChangeObjThread();ReadObjThread t2 = new ReadObjThread();t1.start();t2.start();Thread.sleep(1000);t1.suspendMe();System.out.println("suspend t1 2 sec");Thread.sleep(20000);System.out.println("resume t1");t1.resumeMe();}public static class ChangeObjThread extends Thread{volatile boolean suspendme = false;public void suspendMe(){suspendme = true;}public void resumeMe() {suspendme = false;synchronized(this){notify();}}@Overridepublic void run() {while (true) {synchronized (this) {while (suspendme) {try {wait();		//运用等待实现挂起} catch (InterruptedException e) {e.printStackTrace();}}}synchronized(u){System.out.println("in ChangeObjThread");}Thread.yield();}}}public static class ReadObjThread extends Thread{@Overridepublic void run() {while(true){synchronized (u) {System.out.println("in ReadObjThread");}Thread.yield();}}}
}

8 等待线程结束(join)和谦让(yield)

public final void join() throws InterruptedException
public final synchronized void join(long millis) throws InterruptedException
  • join()表示无限等待,它会一直阻塞当前线程,直到目标线程执行完毕。yield()给出了一个
    最大等待时间,如果超过时间,就会继续往下执行。

  • join()的本质是调用线程wait()在当前线程对象实例上当线程执行完成后,被等待的线程 在退出时调用notifyAll通知所有线程继续执行,因此不要在THread对象上使用类似wait、notify等方法,可能会影响api工作。

  • Thread.yield 一旦执行,会使当前线程让出CPU。但是并不代表不执行,会有一定几率分配到

public class GoodSuspend {public volatile static int i = 0;public static class AddThread extends Thread {@Overridepublic void run() {for (i = 0; i < 100000000; i++) {}}}public static void main(String[] args) throws InterruptedException {AddThread at = new AddThread();at.start();at.join();System.out.println(i);}
}

3 volatile 与java内存模型(JMM)

1 java内存模型:围绕着原子性、有序性和可见性展开的。但是可以利用关键字或特殊操作,告诉虚拟机有些地方需要特别
注意,比如 volatile。
2 volatile:

  • 使用 volatile 去申明一个变量时,在程序范围内的所有其他线程“可见”的,虚拟机就会小心处理这种情况;
  • volatile并不能代替锁,也无法保证一些复合操作的原子性,当两个线程同时修改数据时,依然会产生冲突
  • volatile能保证数据的可见性有序性
//volatile无法保证一些复合操作
public class GoodSuspend {static volatile int i = 0;public static class PlusTask implements Runnable{@Overridepublic void run() {for (int k = 0; k < 10000; k++){i++;};}}public static void main(String[] args) throws InterruptedException {Thread[] task = new Thread[10];for (int i = 0; i < 10; i++) {task[i] = new Thread(new PlusTask());task[i].start();}for (Thread thread : task) {thread.join();}System.out.println(i);}
}

4 线程组


  1. 和一个篮子一样,篮子里的每个水果是线程。
public class ThreadGroupName implements Runnable {static volatile int i = 0;public static void main(String[] args) {ThreadGroup tg = new ThreadGroup("PrintGroup");Thread t1 = new Thread(tg, new ThreadGroupName(), "T1");	//定义线程并加入到线程组Thread t2 = new Thread(tg, new ThreadGroupName(), "T2");t1.start();t2.start();System.out.println(tg.activeCount());tg.list();}@Override//输出线程信息public void run() {String groupAndName = Thread.currentThread().getThreadGroup().getName() + Thread.currentThread().getName();while (true) {System.out.println("I am group " + groupAndName);try {Thread.sleep(3000);} catch (InterruptedException e) {e.printStackTrace();}}}
}

5 驻守后台:守护线程(Daemon)


  • 守护线程:系统的守护者,默默完成系统的一些系统性的服务,比如垃圾回收线程、JIT线程就可以理解为守护线程。与之相对应的是用户线程(系统的工作线程)。
  • 要在start()之前设置守护线程,否则抛出异常,当成用户线程使用。
Thread t = new DaemonT();
t.setDaemon(true);	//设置守护线程
t.start();

6 线程优先级:先做重要的事


  • 优先级越高,资源竞争越有优势,更可能抢占资源。
  • 优先级产生的后果无法精准控制,可能出现低优先级一直抢占不到资源,一直无法运行,从而产生饥饿现象.
  • 自己在应用层解决线程调度的问题。
    • 数字越大优先级越高;有效范围在1-10。
public class PriorityDemo{public static void main(String[] args) {//高权限和低权限的线程做同一件事HightPriority h = new HightPriority();LowPriority l = new LowPriority();h.setPriority(Thread.MAX_PRIORITY);//线程设置为高权限l.setPriority(Thread.MIN_PRIORITY);//线程设置为低权限l.start();h.start();}//~做同一件事情总是高权限线程先完成public static class HightPriority extends Thread{static int count = 0;public void run(){while(true){synchronized (PriorityDemo.class) {//使用同步产生资源竞争,而权限高低会去竞争锁资源count++;if (count > 1000000) {System.out.println("HightPriority is complete!");break;}}}}}public static class LowPriority extends Thread{static int count = 0;public void run(){while(true){synchronized (PriorityDemo.class) {count++;if (count > 1000000) {System.out.println("LowPriority is complete!");break;}}}}}
}

7 线程安全与synchronized


  • 多线程的写入冲突(线程不安全):当两个线程同时修改一个共享对象,产生覆盖的现象
    比如,有一个共享对象int i,线程A和线程B都对i 累加10000次,我们想要的结果是20000,但我们得到的结果总是小于这个值。

  • 即使用volatile这种关键字也是如此,因为volatile不能解决两个线程同时修改共享对象的问题。

public class AccountingVol implements Runnable{public static volatile int i = 0;@Overridepublic void run() {for (int k = 0; k < 1000000; k++) {i++;}}public static void main(String[] args) throws InterruptedException {AccountingVol v1 = new AccountingVol();Thread t1 = new Thread(v1);  //此行和下面一行的Runnable实例一定要是同一个,这样才能保证在两个线程工作时,关注到同一个对象锁上,从而保证线程安全。Thread t2 = new Thread(v1);t1.start();t2.start();t1.join();	//主线程愿意等到该线程执行完再执行t2.join();System.out.println(i);}
}
  • 使用 synchronized 来解决线程安全的问题
    • 用法:
      • 指定加锁对象:对给定对象加锁,进入同步代码前要获得给定对象的锁。
      • 直接作用于实例对象:相当于对当前实例加锁,…。
      • 直接作用于静态方法:相当于对当前类加锁,进入同步块要获得当前类的锁。
    • 当线程进入被synchronized包裹的代码块,必须先请求锁,如果有其他线程正在持有这把锁,则新到的线程就必须等待。
//将上例中的run加上一个同步块
synchronized (v1) {		//同步块,只有一个持有锁的线程可进入for (int k = 0; k < 1000000; k++) {i++;}
}
  • 可将synchronized关键字作用于一个实例方法:意思是进入该方法前,线程需获得当前对象实例的锁。
//上面同步块代码转为一个方法,这种事获取当前对象实例的锁
public synchronized void increase(){i++;
}
for (int k = 0; k < 1000000; k++) {this.increase();
}
  • 想要保证两个线程的线程安全,必须要两个线程都指向同一个Runnable实例接口,这样才能使两个线程关注到同一个对象锁上,既要使用同一把锁,才能保证线程安全,使用下面方法也可以正确执行。
//这样使用的是当前类的锁,即使不是同一个Runnable对象,也可以正确执行
public static synchronized void increase(){i++;
}

8 程序中的幽灵:隐藏的错误

  • 案例:比如两个数相加导致int的溢出,就会导致出现负数的情况

  • 并发下的 ArrayList:ArrayList 是不安全的,可用 Vector 代替 ArrayList

  • 并罚下的诡异的 HashMap:

    • 可能有三种情况:
      • 1 程序正常结束;2 程序正常结束,不符合预期; 3 程序死循环(链表遭到破坏,链表成环);
  • 错误的加锁:

    • 最好别加在Integer对象上,Integer对象在做++运算时是创建一个新的Integer对象的,String对象也是如此。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/330987.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

ReviewForJob(3)表、栈和队列

【0】表ADT1&#xff09;intro&#xff1a;我们把 形如 A1, A2, A3, ..., An 的结构称为表&#xff1b;2&#xff09;表的实现&#xff1a; 数组&#xff08;循环数组&#xff09; 或 链表 或 双链表 或 循环链表实现&#xff1b;3&#xff09;表的插入&#xff0c;删除操作可以…

2017一季度JAVA面试题锦集

转载自 2017一季度JAVA面试题锦集 1、如何实现分布式事务&#xff0c;你们公司是怎么解决的&#xff1f; 2、HashMap数据结构及实现原理&#xff0c;其链表是用来解决什么问题的 3、可以自定义java.lang.String类吗&#xff0c;说明为什么 4、redis 1&#xff09;有哪几种类型的…

JDK并发包

JDK提供了大量实用的API和框架&#xff0c;来支持JDK内部功能&#xff1a; 介绍更多多线程控制方法&#xff0c;比如之前的synchronized&#xff1b;介绍JDK中对线程池的支持&#xff0c;提高线程调度性能&#xff1b;向大家介绍JDK的一些并发容器。 1 多线程的团队协作&…

ReviewForJob——希尔排序(缩小增量排序)之塞奇威克增量序列

【0】README 0&#xff09;希尔排序是基于插入排序的。将插入排序算法 内for循环中的所有 1 改为增量就可以。。bingo。。 插入排序源码 1&#xff09;本文旨在给出 希尔排序&#xff08;缩小增量排序&#xff09;之塞奇威克增量序列 的源码实现&#xff1b; 2&#xff09;为…

稍微有点难度的10道java面试题,你会几道?

转载自 稍微有点难度的10道java面试题&#xff0c;你会几道&#xff1f; 1、jvm对频繁调用的方法做了哪些优化&#xff1f; 2、常见的攻击手段有哪些&#xff1f;如何防范&#xff1f; 3、restful api有哪些设计原则&#xff1f; 4、hessian是做什么用的&#xff1f;它的…

重新学习Spring一--Spring在web项目中的启动过程

1 Spring 在web项目中的启动过程 Spring简介 Spring 最简单的功能就是创建对象和管理这些对象间的依赖关系&#xff0c;实现高内聚、低耦合。&#xff08;高内聚&#xff1a;相关性很强的代码组成&#xff0c;既单一责任原则&#xff1b;低耦合&#xff1a;耦合指块间联系&…

ReviewForJob——堆排序

【0】README1&#xff09;本文旨在给出 推排序的源码实现&#xff1b;堆排序是基于二叉树的数组实现的&#xff1b;【1】堆排序步骤step1&#xff09;对排序数据建堆&#xff0c;执行 n 次 insert 操作&#xff08;基于上滤操作&#xff09;&#xff1b;每次 insert 包括 将 新…

重新学习Spring2——IOC和AOP原理彻底搞懂

一、AOP 1 Spring AOP 的实现原理 是对OOP编程方式的一种补充。翻译过来为“面向切面编程”。 1 AspectJ是静态代理的增强&#xff1a;所谓静态代理就是AOP框架会在便一阶段生成AOP代理类&#xff0c;也叫编译器增强。 2 使用Spring AOP 与AspectJ 的静态代理不同&#xff0c…

厉害了,关于String的10道经典面试题

转载自 厉害了&#xff0c;关于String的10道经典面试题 1、String是基本数据类型吗&#xff1f; 2、String是可变的话&#xff1f; 3、怎么比较两个字符串的值一样&#xff0c;怎么比较两个字符串是否同一对象&#xff1f; 4、switch中可以使用String吗&#xff1f; 5、String …

ReviewForJob——快速排序(基于插入排序)+快速选择(快速排序变体)

【0】README 0&#xff09;本文旨在给出 快速排序 的 源码实现和源码分析&#xff08;分析它的坑&#xff09;&#xff1b; 2&#xff09;要知道 在 元素个数小于10的时候&#xff0c;快速排序不如插入排序&#xff1b;注意快速排序选取枢纽元 时 所使用的方法是 三数中值分割…

Spring boot web(2):web综合开发

1 web开发 Spring boot web 开发非常简单&#xff0c;其中包括常用的 json输出、filters、property、log等 1.1 json接口开发 在以前的Spring 开发我么提供json 的做法&#xff1a; 添加jackjson 等相关jar包配置Spring controller扫描对接的方法添加ResponseBody 而在Spri…

10道腾讯的Java面试题

转载自 10道腾讯的Java面试题 下面总结10道面试腾讯的Java面试题。 1、说几种常见的攻击方式及预防手段。 2、http1.x和http2.x的区别。 3、mysql查询语句怎么做性能分析。 4、你知道哪几种排序算法&#xff1f; 5、HashMap和HashTable的区别&#xff0c;并说明其底层实现数据…

ReviewForJob——桶式排序+基数排序(==多次桶式排序)

【0】README 1&#xff09;本文旨在 给出 ReviewForJob——桶式排序基数排序&#xff08;多次桶式排序&#xff09; 的 代码实现和代码分析&#xff1b; 2&#xff09;桶式排序基础参见 http://blog.csdn.net/pacosonswjtu/article/details/49685749&#xff0c; 基数排序基…

Spring boot(3):Spring boot中Redis 的使用

Spring boot除了常用的数据库支持外&#xff0c;对nosql数据库也进行了封装自动化。 1 Redis介绍 Redis 是目前业界使用最广泛的内存数据存储。相比memcached&#xff0c; &#xff08;1&#xff09;Redis支持更丰富的数据结构&#xff0c;例如hashes&#xff0c;lists&#x…

Java List面试题汇总

转载自 Java List面试题汇总 1、你知道的List都有哪些&#xff1f; 2、List和Vector有什么区别&#xff1f; 3、List是有序的吗&#xff1f; 4、ArrayList和LinkedList的区别&#xff1f;分别用在什么场景&#xff1f; 5、ArrayList和LinkedList的底层数据结构是什么&#…

ReviewForJob——拓扑排序+最短路径算法(有权+无权)

【0】README 1&#xff09;本文旨在给出 拓扑排序最短路径算法&#xff08;有权无权&#xff09; 的源码实现 和 分析&#xff0c;内容涉及到 邻接表&#xff0c; 拓扑排序&#xff0c; 循环队列&#xff0c;无权最短路径&#xff08;广度优先搜索&#xff09;&#xff0c;有权…

Spring boot (5):Spring data jpa 的使用

总结&#xff1a; jpa是什么&#xff0c;spring data jpa是什么&#xff1f; jpa是一套规范&#xff0c;不是一套产品。jpa是一套规范&#xff0c;不是一套产品。 spring data jpa是spring基于ORM框架、JPA规范的基础上封装的一套JPA应用框架&#xff0c;提供了包括增删改等在…

Java Map集合面试题汇总

转载自 Java Map集合面试题汇总1、 你都知道哪些常用的Map集合?2、Collection集合接口和Map接口有什么关系&#xff1f;3、HashMap是线程安全的吗&#xff1f;线程安全的Map都有哪些&#xff1f;性能最好的是哪个&#xff1f;4、使用HashMap有什么性能问题吗&#xff1f;5、Ha…

ReviewForJob——二叉堆优先队列的实现(三种堆节点类型——int + struct HeapNode + struct HeapNode*)

【0】README 1&#xff09;本文旨在给出 二叉堆优先队列的实现 的代码实现和分析&#xff0c; 而堆节点类型 不外乎三种&#xff1a; 一&#xff0c; 基本类型如int&#xff1b; 二&#xff0c;结构体类型 struct HeapNode&#xff1b; 三&#xff0c;结构体指针类型 struct H…

Spring boot(六):如何优雅的使用mybatis

总结 hibernate 和 mybatis 的区别 hibernate的特点是所有的sql都用java代码生成&#xff0c;不用跳出程序去&#xff08;看&#xff09;sql&#xff0c;发展到最顶端就是Spring data jpa了。 mybatis初期使用比较麻烦&#xff0c;需要各种配置文件、实体类、dao层映射关联、还…