java5线程并发库

  线程并发库是JDK 1.5版本级以上才有的针对线程并发编程提供的一些常用工具类,这些类被封装在java.concurrent包下。

  该包下又有两个子包,分别是atomic和locks两个包。

java.util.concurrent.atomic包

  atomic包提供了一些线程相关的工具类,来实现共享数据在多个线程中保持安全访问而不用使用 synchronized关键字进行同步。下面是该报下的一些类。

这里就拿AtomicInteger类来举例,其他类的操作基本上和该类差不多。在JDK的API中说该类可以以原子的方式操作int值,通俗的说就是该类提供了一下对整数类型变量的操作使用该类可以确保在多个线程中访问同一个整数资源时及时不适用锁机制来保持同步也依然能够确保该变数据的安全。下面是给类提供的一些方法。

 package cn.wz.traditional.wf;

 import java.util.concurrent.atomic.AtomicInteger;

 /**
* Created by WangZhe on 2017/5/8.
*/
public class AtomicTest {
static AtomicInteger data =new AtomicInteger(10);
public static void main(String[] args) {
new Thread(new Runnable() {
public void run() {
int resoult = data.addAndGet(10);
System.out.println(resoult);
}
}).start();
new Thread(new Runnable() {
public void run() {
int resoult = data.get();
System.out.println(resoult);
}
}).start();
}
}

以addAndGet方法为例的一个demo

那么Atomic包中的类为什么能够实现数据操作的原始性呢?这个我就不得而知了,因为前sun公司并没有把它体现在源码中。我只知道在addAndGet方法中调用get()方法获取变量的原有值,而get方法中返回的value字段被volatile关键字标示,该关键子线程每次获取该变量的值时都会去主内存区获取该变量最新的值,但是这里值得注意的是volatile关键字并不能像synchronized关键字一样确保变量的原子性,至于AtomicInteger是如何确保其原子性的我也不得而知,希望有知道的大神能够分享下,再此先谢过了!下面附上addAndGet方法的源码.

该方法实现被前sun公司隐藏。

Unsafe类的compareAndSwapInt方法(真正的为变量赋值操作)被隐藏

好了其源码就看到这里了其它的类和方法也都差不多,如果有兴趣你可以自己看看源码(然而并没有什么卵用,呵呵),其实我们也不用纠结于其实怎么实现的我们只要知道其可以确保原子性,在需要的是后能够使用就可以了,其和 synchronized同步代码块而言效率和性能是较高的,但其只能适用于一些简单的赋值运算操作,因为我们可以看到其并没有提供乘除以及其它的复杂操作。

java.util.concurrent.locks包

  该包提供了一些关于线程锁相关的一些接口和类,我们之前使用synchronized关键字只能设置对象、类、变量等固定的锁,而是用该包则可以时锁变得更加灵活和广泛,该包有三大接口

Condition:ConditionObject 监视器方法(waitnotifynotifyAll)分解成截然不同的对象,以便通过将这些对象与任意 Lock 实现组合使用,为每个对象提供多个等待 set(wait-set)。

 Lock:Lock 实现提供了比使用 synchronized 方法和语句可获得的更广泛的锁定操作。

ReadWriteLock:ReadWriteLock 维护了一对相关的,一个用于只读操作,另一个用于写入操作。

Lock 接口方法摘要:

  

 package cn.wz.traditional.wf;

 import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock; /**
* Created by WangZhe on 2017/5/8.
*/
public class LockDemo {
static int data=5;
public static void main(String[] args) {
final Lock lock=new ReentrantLock(true);
new Thread(new Runnable() {
public void run() {
lock.lock();
try {
System.out.println("线程1获取锁\t时间:"+System.currentTimeMillis());
data+=5;
System.out.println("线程1休眠1秒钟\t正在等待该所的线程:"+((ReentrantLock)lock).getQueueLength());
System.out.println(data);
Thread.currentThread().sleep(1000);
}catch (Exception e){
lock.unlock();
}finally {
lock.unlock();
};
}
}).start();
new Thread(new Runnable() {
public void run() {
lock.lock();
try {
System.out.println("线程2获取锁\t时间:"+System.currentTimeMillis());
System.out.println(data);
}catch (Exception e){
lock.unlock();
}finally {
lock.unlock();
};
}
}).start();
}
}

LockDemo

从上面的demo中可以看出Lock接口不再指定同步锁定的对象,而是一起本身为锁对象别synchronized更加灵活且没有synchronized关键字必须在同一个代码块儿的限制。上面demo中使用的ReentrantLock类是Lock接口的实现类Lock接口下面还提供了控制读写锁的实现类:ReentrantReadWriteLock.ReadLock和ReentrantReadWriteLock.WriteLock两个类,而这两个类都是ReentrantReaWriteLock类的内部类,如图所示:

而ReentrantReadWriteLock类是ReadWriteLock接口的实现类。这里就在顺便说一下这个接口。该接口只有两个方法定义如下所示:

一个适用于获取ReadLock的锁另一个是用于获取WriteLock的锁这两个锁一般成对出现用来分离数据的读和写进行加锁,比如说一个线程对A资源进行写入操作时另一个线程读取A资源时就需要等待上一个线程释放A资源的写入锁才能获取A资源的读取锁进行数据读取,反之亦然。

 package cn.wz.traditional.wf;

 import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantReadWriteLock; /**
* Created by WangZhe on 2017/5/8.
*/
public class ReadLockDemo {
static int data=10; public static void main(String[] args) {
final ReentrantReadWriteLock RWlock = new ReentrantReadWriteLock();//获取读写锁实例
final ReentrantReadWriteLock.ReadLock Rlock=RWlock.readLock();//获取读取所实例
final ReentrantReadWriteLock.WriteLock Wlock=RWlock.writeLock();//获取写入锁实例
new Thread(new Runnable() {
public void run() {//线程一
Wlock.lock();
try{
data=5;
System.out.println(data);
System.out.println("线程一写入数据完毕保持写入锁休眠10秒钟");
System.out.println("当前时间:"+System.currentTimeMillis());
Thread.currentThread().sleep(10000);
}catch (Exception e){
Wlock.unlock();
}finally {
Wlock.unlock();
}
}
}).start();
new Thread(new Runnable() {
public void run() {//线程二
Rlock.lock();
try{
System.out.println("线程二获取读取锁,开始进行数据读取");
System.out.println("当前时间:"+System.currentTimeMillis());
System.out.println(data);
}catch (Exception e){
Rlock.unlock();
}finally {
Rlock.unlock();
}
}
}).start();
}
}

读写锁演示demo

Condition接口

Condition接口的出现代替了Object对象的三个改变线程的方法(wait、notify、notifyall)如果说Lock相当于synchronized关键字那Condition就相当于Object监视器的方法。下面是该接口的方法

其中await方法相当于Object的wait方法,Signal方法相当于Object的notify方法,signalAll方法相当于Object对像的notifyAll方法。这里不再详细说明直接通过demo来演示效果。场景如下:

AB两个线程同时操作资源i A线程对i进行加操作,B线程对i进行减操作,当i大于5时A线程等待让B线程进行减操作,反之B线程等待让A线程进行加操作。

 package cn.wz.traditional.wf;

 import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock; /**
* Created by WangZhe on 2017/5/9.
*/
public class ConditionDemo {
public static void main(String[] args) {
final Lock lock=new ReentrantLock();
final Condition conditionInc=lock.newCondition();;
final Condition conditionDec=lock.newCondition();
final DemoData data=new DemoData();
new Thread(new Runnable() {
public void run() {
lock.lock();
try {
for (int j = 0; j < 50; j++) {
while (data.getI() > 5) {
conditionInc.await();
}
data.inc();
conditionDec.signal();
}
} catch (Exception e) {
lock.unlock();
} finally {
lock.unlock();
}
}
}).start();
new Thread(new Runnable() {
public void run() {
lock.lock();
try{
for(int j=0;j<50;j++) {
while (data.getI() <= 5) {
conditionDec.await();
}
data.dec();
conditionInc.signal();
}
}catch (Exception e){
lock.unlock();
}finally {
lock.unlock();
}
}
}).start();
}
static class DemoData{
private int i; public DemoData(int i) {
this.i = i;
} public DemoData() {
}
public void inc(){
i++;
System.out.println("线程A进行加操作后i的值:"+i);
}
public void dec(){ i--;
System.out.println("线程B进行减操作后i的值:"+i);
}
public int getI() {
return i;
} public void setI(int i) {
this.i = i;
}
}
}

Demo

java线程池的应用

我们知道线程一旦死亡就无法复活(进行重新启动线程。)但是在黑马的面试题中关于java并发的问题中有这样一道面试题:“如何重新启动一个已经死亡的线程?”。刚开始碰到这个问题的人可能会很惊讶,为什么会有这样的面试题呢?我们先来看下面一个demo算不算是重新启动了一个死亡的线程。

 package cn.wz.traditional.wf;

 import com.sun.org.apache.xpath.internal.SourceTree;

 import java.util.concurrent.Executor;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.ThreadPoolExecutor; /**
* Created by WangZhe on 2017/5/9.
*/
public class ExecutorSignlePool {
public static void main(String[] args) {
ExecutorService executorService = Executors.newSingleThreadExecutor();
executorService.execute(new MyRunnable()); }
static class MyRunnable implements Runnable{
public void run() {
for (int i=0;i<10;i++){
if(i==5)
Thread.currentThread().stop();
System.out.println("hello");
}
}
}
}

Demo

从上面例子中可以看到我没在循环到第五次的时候停止当前线程使其死亡,但是我们从结果中可以看到程序并没有结束,那就说明还有线程正在运行,那我们是否可以这样假设当停止当前线程时线程池(executorService)一直试图重新启动线程但重启之后立马又被我们的代码关掉所以一直执行不下去,但也不会结束。那具体是不是这样我也不知道(哈哈),但我知道的是单例线程池(也就是我们上边demo中的executorService)中只能存在一个线程,当期线程死亡后会立马创建一个新的线程, 从一定程度上也可以说是重新启动了一个线程,而且即使线程执行完毕也不会结束除非手动停止线程池

 package cn.wz.traditional.wf;

 import com.sun.org.apache.xpath.internal.SourceTree;

 import java.util.concurrent.Executor;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.ThreadPoolExecutor; /**
* Created by WangZhe on 2017/5/9.
*/
public class ExecutorSignlePool {
public static void main(String[] args) {
ExecutorService executorService = Executors.newSingleThreadExecutor();
MyRunnable myRunnable = new MyRunnable();
executorService.execute(myRunnable);
executorService.execute(myRunnable); }
static class MyRunnable implements Runnable{
public void run() {
System.out.println("开始执行");
System.out.println("hello");
}
}
}

demo

除了单线程池意外我们开可以创建固定大小的线程池(newFixedThreadPool方法创建)和缓存线程池(newCachedThreadPool方法创建)这两个方法都返回ExecutorService类型对象。

固定大小的线程池:该池中的线程个数是固定的当线程任务(Runnable对象)个数大于设置的线程个数时超出的任务等待之前任务执行后再执行。

缓存线程池:该池初始没有线程,当有任务进来时创建线程并在执行结束后缓存一段时间。在改时间之内有新的任务进来则不再创建新线程直接使用原有线程。

java线程(四)的更多相关文章

  1. java线程四种状态

    一个线程可以有四种状态: 1.新(new), 即线程刚刚创建,而并未执行 2.可运行(runnable),意味着一旦时间分片机制有空闲的CPU周期提供给一个线程,那个线程便可立即开始运行.因此,线程可 ...

  2. Java线程专栏文章汇总(转)

    原文:http://blog.csdn.net/ghsau/article/details/17609747 JDK5.0之前传统线程        Java线程(一):线程安全与不安全 Java线程 ...

  3. Java线程专栏文章汇总

        转载自 http://blog.csdn.net/ghsau/article/details/17609747 JDK5.0之前传统线程        Java线程(一):线程安全与不安全 J ...

  4. 四种Java线程池用法解析

    本文为大家分析四种Java线程池用法,供大家参考,具体内容如下 http://www.jb51.net/article/81843.htm 1.new Thread的弊端 执行一个异步任务你还只是如下 ...

  5. Java进阶(四十三)线程与进程的区别

    Java进阶(四十三)线程与进程的区别 1.线程的基本概念   概念:线程是进程中执行运算的最小单位,是进程中的一个实体,是被系统独立调度和分派的基本单位,线程自己不拥有系统资源,只拥有一点在运行中必 ...

  6. Java并发编程:Java的四种线程池的使用,以及自定义线程工厂

    目录 引言 四种线程池 newCachedThreadPool:可缓存的线程池 newFixedThreadPool:定长线程池 newSingleThreadExecutor:单线程线程池 newS ...

  7. Java ExecutorService四种线程池的例子与说明

    1.new Thread的弊端 执行一个异步任务你还只是如下new Thread吗? new Thread(new Runnable() { @Override public void run() { ...

  8. 面试题:四种Java线程池用法解析 !=!=未看

    1.new Thread的弊端 执行一个异步任务你还只是如下new Thread吗? 1 2 3 4 5 6 7 8 new Thread(new Runnable() {     @Override ...

  9. Java ExecutorService四种线程池的例子与说明(转发)

    1.new Thread的弊端 执行一个异步任务你还只是如下new Thread吗? new Thread(new Runnable() { @Override public void run() { ...

  10. Java ExecutorService四种线程池及自定义ThreadPoolExecutor机制

    一.Java 线程池 Java通过Executors提供四种线程池,分别为:1.newCachedThreadPool:创建一个可缓存线程池,如果线程池长度超过处理需要,可灵活回收空闲线程,若无可回收 ...

随机推荐

  1. 一文让你从此告别HTTP乱码(二)Response篇

    #circle { background-color: #8fcbec; border: 3px } 概述 开发Web项目的过程中,经常遇到浏览器中显示的内容乱码,或者服务器获取浏览器请求参数时乱码的 ...

  2. flex中过滤掉字符串的空格

    1.先引入import mx.utils.StringUtil;这个包, 在使用StringUtil.trim(); 如:if(StringUtil.trim(this.d1.3.text) ==&q ...

  3. JS页面打开方式丶对话框及页面跳转方式

    一.js页面的三种打开方式 1. window.open 2. window.navigate("url") 跳转到目标页面 3. window.location.href=&qu ...

  4. WEB开发性能优化--核心定义介绍篇(1)

    推荐理由 随着 互联网的蓬勃发展,并且伴随着产品功能的越来越复杂,对于技术人员来说最大的挑战就是如何在保证业务快速发展的同时,也可保证不断复杂的业务对用户体验的影响,其中对用户来说最重要的体验指标是如 ...

  5. Struts2之Validator

    Struts2中提供了数据校验验证数据例如验证邮件.数字等.验证方式有3种:一是通过validate()方法,二是通过Xml,三是使用注解方式. 一.初始化 首先定义一个User类 package c ...

  6. 手机自动化测试:appium源码分析之bootstrap八

    手机自动化测试:appium源码分析之bootstrap八   poptest是国内唯一一家培养测试开发工程师的培训机构,以学员能胜任自动化测试,性能测试,测试工具开发等工作为目标.如果对课程感兴趣, ...

  7. 老李分享:jvm结构简介 2

    2.2.4 Program counter regsiters:程序计数器 类似于PC寄存器,是一块较小的内存区域,通过程序计数器中的值寻找要执行的指令的字节码,由于多线程间切换时要恢复每一个线程的当 ...

  8. linux 压缩与解压

    tar -cvf test.tar test  ----将test文件夹打包成test.tar. # tar -xvf test.tar     ----将test.tar 进行拆解,从中抽取文件 # ...

  9. 自行扩展 FineUIMvc 通知对话框(多个并排显示不重叠,支持最新的显示在最上方)

    声明:FineUIMvc(基础版)是免费软件,本系列文章适用于基础版. 这篇文章我们将改造 FineUIMvc 默认的通知对话框,使得同时显示多个也不会重叠.并提前出一个公共的JS文件,供大家使用. ...

  10. 利用 force recovery 解决服务器 crash 导致 MySQL 重启失败的问题

    小明同学在本机上安装了 MySQL 5.7.17 配合项目进行开发,并且已经有了一部分重要数据.某天小明在开发的时候,需要出去一趟就直接把电脑关掉了,没有让 MySQL 正常关闭,重启 MySQL 的 ...