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的更多相关文章

  1. java多线程----JUC集合”01之 框架

    java集合的架构.主体内容包括Collection集合和Map类:而Collection集合又可以划分为List(队列)和Set(集合). 1. List的实现类主要有: LinkedList, A ...

  2. Java多线程—JUC原子类

    根据修改的数据类型,可以将JUC包中的原子操作类可以分为4类. 1. 基本类型: AtomicInteger, AtomicLong, AtomicBoolean ;2. 数组类型: AtomicIn ...

  3. Java多线程系列--“JUC锁”03之 公平锁(一)

    概要 本章对“公平锁”的获取锁机制进行介绍(本文的公平锁指的是互斥锁的公平锁),内容包括:基本概念ReentrantLock数据结构参考代码获取公平锁(基于JDK1.7.0_40)一. tryAcqu ...

  4. Java多线程系列--“JUC锁”04之 公平锁(二)

    概要 前面一章,我们学习了“公平锁”获取锁的详细流程:这里,我们再来看看“公平锁”释放锁的过程.内容包括:参考代码释放公平锁(基于JDK1.7.0_40) “公平锁”的获取过程请参考“Java多线程系 ...

  5. Java多线程系列--“JUC锁”10之 CyclicBarrier原理和示例

    概要 本章介绍JUC包中的CyclicBarrier锁.内容包括:CyclicBarrier简介CyclicBarrier数据结构CyclicBarrier源码分析(基于JDK1.7.0_40)Cyc ...

  6. Java多线程系列--“JUC锁”02之 互斥锁ReentrantLock

    本章对ReentrantLock包进行基本介绍,这一章主要对ReentrantLock进行概括性的介绍,内容包括:ReentrantLock介绍ReentrantLock函数列表ReentrantLo ...

  7. Java多线程系列--“JUC锁”01之 框架

    本章,我们介绍锁的架构:后面的章节将会对它们逐个进行分析介绍.目录如下:01. Java多线程系列--“JUC锁”01之 框架02. Java多线程系列--“JUC锁”02之 互斥锁Reentrant ...

  8. java多线程系类:JUC线程池:03之线程池原理(二)(转)

    概要 在前面一章"Java多线程系列--"JUC线程池"02之 线程池原理(一)"中介绍了线程池的数据结构,本章会通过分析线程池的源码,对线程池进行说明.内容包 ...

  9. java多线程系类:JUC线程池:02之线程池原理(一)

    在上一章"Java多线程系列--"JUC线程池"01之 线程池架构"中,我们了解了线程池的架构.线程池的实现类是ThreadPoolExecutor类.本章,我 ...

随机推荐

  1. Nginx反向代理实现Tomcat负载均衡

    这篇短文主要介绍Tomcat的集群和用Nginx反向代理实现Tomcat负载均衡. 1.首先需要对一些知识点进行扫盲(对自己进行扫盲,囧): 集群(Cluster) 简单来说就是用N台服务器构成一个松 ...

  2. 类似fabric主机管理demo

    类似于fabric的主机管理系统 可以批量对主机进行操作 批量上传文件 批量下载文件 批量执行命令 demo代码 #!/usr/bin/env python # -*- coding:utf-8 -* ...

  3. Struts2(四)Struts2配置文件的配置

    Struts2的常见配置 1.Struts2的配置文件的加载顺序: 每次从客户端发送到请求到服务器都要先从Struts2的核心过滤器StrutsPrepareAndExeccuteFilter,这个过 ...

  4. ASP.NET Core源码学习(一)Hosting

    ASP.NET Core源码的学习,我们从Hosting开始, Hosting的GitHub地址为:https://github.com/aspnet/Hosting.git 朋友们可以从以上链接克隆 ...

  5. iOS - IM 即时通讯

    1.即时通讯技术 即时通讯(IM:Instant Messaging):又称实时通讯,支持用户在线实时交谈,允许两人或多人使用网络实时的传递文字消息.文件.语音与视频交流. 即时通讯在开发中使用的场景 ...

  6. 一个完整的springmvc + ajaxfileupload实现图片异步上传的案例

    一,原理 详细原理请看这篇文章 springmvc + ajaxfileupload解决ajax不能异步上传图片的问题.java.lang.ClassCastException: org.apache ...

  7. 异常-----web.xml文件报错 Multiple annotations found at this line: - cvc-complex-type.2.4.b: The content of element 'welcome-file-list' is not complete. One of '{"http://java.sun.c

    1,检查抬头是不是有问题. <?xml version="1.0" encoding="UTF-8"?><web-app version=&q ...

  8. 关于js中 toFixed()的一个小坑

    作为一名前端,大家都应该知道,toFixed()的作用,toFixed()经常用于前台与后台数据格式的转换,套用下w3c上面的定义: 定义和用法toFixed(n) 方法可把 Number 四舍五入为 ...

  9. 编写第一个Flutter App(翻译)

    博客搬迁至http://blog.wangjiegulu.com RSS订阅:http://blog.wangjiegulu.com/feed.xml 以下代码 Github 地址:https://g ...

  10. ViewGroup事件分发机制解析

    最近在看View的事件分发机制,感觉比复杂的地方就是ViewGrop的dispatchTouchEvent函数,便对照着源码研究了一下.故名思意这个函数起到的作用就是分发事件,在具体分析之前还要说明几 ...