Java多线程JUC
1. volatile 关键字
多线程访问的时候,一个比较严重的问题就是内存不可见,其实在内存访问的时候每一个线程都有一个自己的缓冲区,每次在做修改的时候都是从主存取到数据,然后放到自己的缓冲区中,在做完修改之后放回主存。这样每一个线程之间的变量是不可见的。造成读到的数据可能始终就是错误的,因此有一个关键字可以使得这个共享变量称为透明的。就好像所有的操作就直接是在内存中操作一样,因为他一直不停的去同步主存的数据。
2.原子性
i++ 这个运算,其实在底层低用的就是临时变量的方式,这样的话虽然是一个表达式,但是在多线程的时候就会出现安全问题。
package atomic;
/**
* @Author: lwen
* @Date: Created in 2017/8/19 15:26
* @Description:
*/
class Test implements Runnable{
private volatile int i=0;
@Override
public void run() {
try {
Thread.sleep(200);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(i++);
}
}
public class Main {
public static void main(String[] args) {
Test t=new Test();
for (int i = 0; i < 10; i++) {
new Thread(t).start();
}
}
}
最后运行的结果,显然就是 volatile 这个关键字他只是让变量课件也就是都是在主存中操作,但是他没有互斥的作用简单来说没有锁来控制,他们都及时的从主存里面拿到了数据,但是他们拿到最新的数据了,正在运算的时候有人提交了结果,所以导致重复元素。最根本原因是 i++ 有三步操作,读,运算,写
1
3
2
0
4
7
6
5
8
8
Process finished with exit code 0
java 底层提供了一些原子性的变量,例如 AtomicInteger 这些东西他们既然是源自的首先就是可见的。这些东西的底层主要是使用了 CAS ( CompareAndSet ) 算法,CAS 算法主要是操作系统在硬件上提供的支持。
这个算法有三个重要的参数:第一个就是 V 就是运算前从内存读取的值 A 写入前从内存中读取的值 B 最终需要写入的值。在写入前做一次判断当且仅当 V == A 时才会写入 B 否则什么操作也不做。
3.ConcurrentHahsMap 安全的 HashMap
这是一个线程安全的 HashMap ,说道线程安全的 HahsMap 自然就有 HashTable 但是这个效率非常的低,主要就是因为他的封锁粒度太大,他锁的是整个 HashTable 也就是两个不相干的 HashTable 也是互斥访问的,在 jdk1.5 以后使用的就是 ConcurrentHahsMap 这个东西那个时候主要使用的锁分段机制,也就是在原来的基础上把 HashTable 分16段,每一段对应一个 HashMap 这样的话两个互不相干的 HashMap 是可以同步访问的。
4.CountDownLatch 闭锁
所谓的闭锁说白了就是该线程会等到洽谈所有线程的代码都运行结束了才开始运行,他的底层实现就是维护一个变量,这个变量就是当前存活的线程的数量,当他减成0了也就是其他的线程都运行完了,此时这个闭锁线程可以开始。例如说我们开十个线程做某一件事情,我们在主线程中统计这十个线程的总的运行时间。
package latch;
import com.sun.javafx.sg.prism.web.NGWebView;
import java.util.concurrent.CountDownLatch;
/**
* @Author: lwen
* @Date: Created in 2017/8/19 16:06
* @Description:
*/
class Latch implements Runnable{
private CountDownLatch latch;
public Latch(CountDownLatch latch) {
this.latch = latch;
}
@Override
public void run() {
System.out.println(Thread.currentThread());
try {
Thread.sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
latch.countDown(); //线程结束以后,需要给维护的变量减一
}
}
public class Main {
public static void main(String[] args) throws InterruptedException {
int start= (int) System.currentTimeMillis();
CountDownLatch downLatch= new CountDownLatch(10); //定义十个线程
Latch latch=new Latch(downLatch);
for (int i = 0; i < 10; i++) {
new Thread(latch).start();
}
downLatch.await(); //当线程没有完全结束的时候,主线程需要等待
int end= (int) System.currentTimeMillis();
System.out.println(end-start);
}
}
4.线程的第三种创建方式
一般我们创建线程我们使用的都是继承 Thread 类,或者实现 Runnable 接口,但是还是主要使用的是实现 Runnable 接口,但是注意这两个方式他们嗾使没有返回值的东西。也就是我么不能多线程没有办法返回一些结果。这里就出现了创建线程的第三种方式,也就是可以得到返回值的方式,就是使用 Callable 接口,这个接口的使用需要使用 FutureTask 类,而这个类实现了 Runnable 和 Future 接口,他的具体的使用方式和 Runnable 接口还是有一点不一样的。
package future;
import org.omg.PortableInterceptor.INACTIVE;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.FutureTask;
/**
* @Author: lwen
* @Date: Created in 2017/8/19 16:23
* @Description:
*/
class Future implements Callable<Integer>{
@Override
public Integer call() throws Exception {
int sum=0;
for (int i = 0; i < 1000; i++) {
sum+=i;
}
return sum;
}
}
public class Main {
public static void main(String[] args) throws ExecutionException, InterruptedException {
Future future=new Future();
FutureTask<Integer> task=new FutureTask<Integer>(future);
new Thread(task).start();
System.out.println(task.get());;//获取最终的返回值,但是注意这个地方的这个方法其实就是一个闭锁,前面的那个县城没有执行完,这个地方是不会执行的
}
}
5.高级同步
解决同步问题总共就有三种方式,分别就是同步代码块,同步函数,和同步锁。
也就是手动的声明 lock 加锁,然后使用 unlock 释放锁
package lock;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
/**
* @Author: lwen
* @Date: Created in 2017/8/19 16:33
* @Description:
*/
class Ticket implements Runnable{
private int ticket=100;
Lock lock=new ReentrantLock();
@Override
public void run() {
while (true) {
lock.lock();
try {
if (ticket != 0) {
try {
Thread.sleep(20);
} catch (InterruptedException e) {
e.printStackTrace();
}
ticket--;
System.out.println(Thread.currentThread().getName() + ":" + ticket);
}
}finally {
lock.unlock(); //解锁必须放在finally里面保证能够执行到
}
}
}
}
public class Main {
public static void main(String[] args) {
Ticket t=new Ticket();
new Thread(t,"窗口一").start();
new Thread(t,"窗口二").start();
new Thread(t,"窗口三").start();
}
}
6.生产者和消费者的线程同步问题
package product;
import java.util.logging.Level;
/**
* @Author: lwen
* @Date: Created in 2017/8/19 16:57
* @Description:
*/
class Clerk {
private int production=0;
public synchronized void get() throws InterruptedException {
while (production>=1){ //notifyAll 可能会形成假唤醒问题,所以说必须要使用while一直判断而不能使用if
System.out.println("已满");
this.wait();
}
System.out.println(Thread.currentThread().getName()+":"+ ++production);
this.notifyAll();
}
public synchronized void sale() throws InterruptedException {
while (production<=0){
System.out.println("卖完");
this.wait();
}
System.out.println(Thread.currentThread().getName()+":"+ --production);
this.notifyAll();
}
}
class Product implements Runnable{
private Clerk clerk;
public Product(Clerk clerk) {
this.clerk = clerk;
}
@Override
public void run() {
for (int i = 0; i < 20; i++) {
try {
Thread.sleep(20);
} catch (InterruptedException e) {
e.printStackTrace();
}
try {
clerk.get();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
class Consumer implements Runnable{
private Clerk clerk;
public Consumer(Clerk clerk) {
this.clerk = clerk;
}
@Override
public void run() {
for (int i = 0; i < 20; i++) {
try {
Thread.sleep(20);
} catch (InterruptedException e) {
e.printStackTrace();
}
try {
clerk.sale();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
public class Main {
public static void main(String[] args) {
Clerk clerk=new Clerk();
Product p=new Product(clerk);
Consumer consumer=new Consumer(clerk);
new Thread(p,"生产者1").start();
new Thread(p,"生产者2").start();
new Thread(consumer,"消费者1").start();
new Thread(consumer,"消费者2").start();
}
}
7.读写锁
排斥写写和读写同时进行
package readandwrite;
import java.util.concurrent.locks.ReadWriteLock;
import java.util.concurrent.locks.ReentrantReadWriteLock;
/**
* @Author: lwen
* @Date: Created in 2017/8/19 17:29
* @Description:
*/
class ReadWriteLockDemo {
private int number=0;
private ReadWriteLock lock=new ReentrantReadWriteLock();
public void read(){
lock.readLock().lock();
try {
System.out.println(Thread.currentThread().getName()+":"+number);
}finally {
lock.readLock().unlock();
}
}
public void write(int number) throws InterruptedException {
lock.writeLock().lock();
Thread.sleep(20);
try {
this.number=number;
System.out.println("write");
}finally {
lock.writeLock().unlock();
}
}
}
public class Main {
public static void main(String[] args) {
ReadWriteLockDemo readWriteLockDemo=new ReadWriteLockDemo();
new Thread(new Runnable() {
@Override
public void run() {
try {
readWriteLockDemo.write(20);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}).start();
for (int i = 0; i < 20; i++) {
new Thread(new Runnable() {
@Override
public void run() {
readWriteLockDemo.read();
}
}).start();
}
}
}
4.线程池
package pool;
import java.util.concurrent.*;
/**
* @Author: lwen
* @Date: Created in 2017/8/19 17:56
* @Description:
*/
class Test implements Runnable{
@Override
public void run() {
System.out.println(Thread.currentThread().getName());
}
}
class Test1 implements Callable<Integer>{
@Override
public Integer call() throws Exception {
int sum=0;
for (int i = 0; i <= 100; i++) {
sum+=i;
}
return sum;
}
}
public class Main {
public static void main(String[] args) throws ExecutionException, InterruptedException {
//注意线程池里面装的都是线程,这些线程到时候再次使用的时候不需要再次创建,也就是代表操作系统不需要再次分配资源,分配pid等等
//而不是说里面装的是任务,这里仅仅就是线程而已
ExecutorService executor= Executors.newFixedThreadPool(10); //固定大小的线程池
ExecutorService executor1=Executors.newSingleThreadExecutor(); //一个线程的线程池
ExecutorService executor2=Executors.newCachedThreadPool(); //动态变化的线程池
for (int i = 0; i < 20; i++) {
executor.submit(new Test());
}
Future<Integer> future=executor1.submit(new Test1());
System.out.println(future.get());
executor.shutdown(); //只有当线程池关闭的时候 程序才会停止
executor1.shutdown();
executor2.shutdown();
}
}
8.线程调度:
线程调度可以决定在多久之后执行什么操作。
package schedule;
import java.util.Random;
import java.util.concurrent.*;
/**
* @Author: lwen
* @Date: Created in 2017/8/19 18:11
* @Description:
*/
public class Main {
public static void main(String[] args) throws ExecutionException, InterruptedException {
ScheduledExecutorService service= Executors.newScheduledThreadPool(5);
for (int i = 0; i < 5; i++) {
Future<Integer> future=service.schedule(new Callable<Integer>() {
@Override
public Integer call() throws Exception {
int random=new Random().nextInt(100);
System.out.println(Thread.currentThread().getName()+":"+random);
return random;
}
},1, TimeUnit.SECONDS);
System.out.println(future.get());
}
service.shutdown();
}
}
Java多线程JUC的更多相关文章
- java多线程----JUC集合”01之 框架
java集合的架构.主体内容包括Collection集合和Map类:而Collection集合又可以划分为List(队列)和Set(集合). 1. List的实现类主要有: LinkedList, A ...
- Java多线程—JUC原子类
根据修改的数据类型,可以将JUC包中的原子操作类可以分为4类. 1. 基本类型: AtomicInteger, AtomicLong, AtomicBoolean ;2. 数组类型: AtomicIn ...
- Java多线程系列--“JUC锁”03之 公平锁(一)
概要 本章对“公平锁”的获取锁机制进行介绍(本文的公平锁指的是互斥锁的公平锁),内容包括:基本概念ReentrantLock数据结构参考代码获取公平锁(基于JDK1.7.0_40)一. tryAcqu ...
- Java多线程系列--“JUC锁”04之 公平锁(二)
概要 前面一章,我们学习了“公平锁”获取锁的详细流程:这里,我们再来看看“公平锁”释放锁的过程.内容包括:参考代码释放公平锁(基于JDK1.7.0_40) “公平锁”的获取过程请参考“Java多线程系 ...
- Java多线程系列--“JUC锁”10之 CyclicBarrier原理和示例
概要 本章介绍JUC包中的CyclicBarrier锁.内容包括:CyclicBarrier简介CyclicBarrier数据结构CyclicBarrier源码分析(基于JDK1.7.0_40)Cyc ...
- Java多线程系列--“JUC锁”02之 互斥锁ReentrantLock
本章对ReentrantLock包进行基本介绍,这一章主要对ReentrantLock进行概括性的介绍,内容包括:ReentrantLock介绍ReentrantLock函数列表ReentrantLo ...
- Java多线程系列--“JUC锁”01之 框架
本章,我们介绍锁的架构:后面的章节将会对它们逐个进行分析介绍.目录如下:01. Java多线程系列--“JUC锁”01之 框架02. Java多线程系列--“JUC锁”02之 互斥锁Reentrant ...
- java多线程系类:JUC线程池:03之线程池原理(二)(转)
概要 在前面一章"Java多线程系列--"JUC线程池"02之 线程池原理(一)"中介绍了线程池的数据结构,本章会通过分析线程池的源码,对线程池进行说明.内容包 ...
- java多线程系类:JUC线程池:02之线程池原理(一)
在上一章"Java多线程系列--"JUC线程池"01之 线程池架构"中,我们了解了线程池的架构.线程池的实现类是ThreadPoolExecutor类.本章,我 ...
随机推荐
- java异常处理、多态
第一:GC是什么? 为什么要有GC? 第二:垃圾回收的优点和原理.并考虑2种回收机制. 第三:垃圾回收器的基本原理是什么?垃圾回收器可以马上回收内存吗?有什么办法主动通知虚拟机进行垃圾回收? 第 ...
- SM4密码算法(附源码)
SM4是我们自己国家的一个分组密码算法,是国家密码管理局于2012年发布的.网址戳→_→:http://www.cnnic.NET.cn/jscx/mixbz/sm4/ 具体的密码标准和算法官方有非常 ...
- Oracle连接出错(一)
1.错误描述 java.sql.SQLException: ORA-0064:error occurred at recursive SQL level 1. ORA-06153:unable to ...
- java.lang.NumberFormatException
1.错误描述 Exception in thread "main" java.lang.NumberFormatException: For input string: " ...
- tcp_wrapper
介绍 对基于tcp协议开发并提供服务的应用程序,所提供的一层访问控制工具 基于库调用实现其功能 * 库名:libwrap 判断服务是否能够由tcp_wrapper进行访问控制 1. 动态编译 ldd命 ...
- 吐血整理:人工智能PDF中文教材资源包2.73G基本包含全部学习资料-人工智能学习书单
吐血整理:人工智能PDF中文教材资源包2.73G基本包含全部学习资料 人工智能学习书单(关注微信公众号:aibbtcom获取更多资源) 文末附百度网盘下载地址 人工神经网络与盲信号处理 人工神经网络与 ...
- Log4j各级别日志重复打印
使用filter进行日志过滤 这个其实是Log4j自带的方案,也是推荐方案,不知道为什么网上的资料却很少提到这点.把log4j.properties配置文件修改成如下: #root日志 log4j.r ...
- mybatis快速入门(二)
这次接着上次写增删改查吧. 现将上节的方法改造一下,改造测试类. package cn.my.test; import java.io.IOException; import java.io.Inpu ...
- 【BZOJ2754】喵星球上的点名(AC自动机)
[BZOJ2754]喵星球上的点名(AC自动机) 题面 BZOJ 题解 友情提示:此题请不要在cogs上提交,它的数据有毒 对于点名串构建\(AC\)自动机 然后把名字丢进去进行匹配, 大力统计一下答 ...
- 【BZOJ1009】GT考试(KMP算法,矩阵快速幂,动态规划)
[BZOJ1009]GT考试(KMP算法,矩阵快速幂,动态规划) 题面 BZOJ 题解 看到这个题目 化简一下题意 长度为\(n\)的,由\(0-9\)组成的字符串中 不含串\(s\)的串的数量有几个 ...