java map 内存可见性_JUC线程创建,volatile内存可见性CAS算法模式和ConcurrentHashMap基础原理...

1.线程的四种创建方式:

1.直接继承Thread的方式去实现线程的创建:

/**

* 创建线程方式一:

*/

public class test01 {

public static void main(String[] args) {

ThreadDemo01 threadDemo01 = new ThreadDemo01();

threadDemo01.start();

}

}

class ThreadDemo01 extends Thread {

@Override

public void run() {

System.out.println(Thread.currentThread().getName());

}

}

1.1通过内部类直接创建,效果和上面是一样的。

//通过内部类直接创建:

public class test02 {

public static void main(String[] args) {

Thread thread = new Thread(){

@Override

public void run() {

System.out.println(Thread.currentThread().getName());

}

};

thread.start();

}

}

底层代码分析:

/* What will be run. */

private Runnable target;

-----------------------------------------

@Override

public void run() {

if (target != null) {

target.run();//在这里,底层给我们写好了,可以直接调用run方法。

}

}

----------------------------------------------

//直接去实现Runnable接口

@FunctionalInterface

public interface Runnable {

/**

* When an object implementing interface Runnable is used

* to create a thread, starting the thread causes the object's

* run method to be called in that separately executing

* thread.

*

* The general contract of the method run is that it may

* take any action whatsoever.

*

* @see     java.lang.Thread#run()

*/

public abstract void run();

}

2.通过实现Runable

//实现Runnable接口

public class testRunable {

public static void main(String[] args) {

new Thread(new TestRunnableDemo(),"Runnable").start();

}

}

class TestRunnableDemo implements Runnable{

@Override

public void run() {

System.out.println(Thread.currentThread().getName());

}

}

从底层来看,一个类去继承Thread和去实现Runnable的本质是一样的,最终的结果都是调用Runnable接口的run方法。

3.实现Callable接口:

public class TestCallable {

public static void main(String[] args) {

//1.创建对应的对象

TestCallableDemo testCallableDemo = new TestCallableDemo();

//2.需要通过FutureTask的实现类的支持,并用于接收运行结果

FutureTask futureTask = new FutureTask<>(testCallableDemo);

//3.开启线程

new Thread(futureTask).start();

//4.接收运行的结果:

try {

String s = futureTask.get();

System.out.println("这个是获取到的值为:"+s);

} catch (InterruptedException e) {

e.printStackTrace();

} catch (ExecutionException e) {

e.printStackTrace();

}

}

}

class TestCallableDemo implements Callable{

@Override

public String call() throws Exception {

System.out.println(Thread.currentThread().getName());

return "Callable";

}

}

Java 5.0 在java.util.concurrent提供了一个新的创建执行线程的方式:Callable接口。

Callable接口类似于Runnable,两者都是为那些实例可能被另一个线程执行的类设计的,但是Runnable不会返回结果,并且无法抛出经过检查的异常,但是Callable是可以有返回结果,并且可以抛出检查的异常的。

Callable需要依赖FutureTask,FutureTask也可以用作闭锁。

1) FutureTask(实现类)实现了RunnableFuture(接口)。

2)RunnableFuture继承了Runnable(接口)和Future(接口)。

4.利用线程池实现:

public class TestThreadPool {

public static void main(String[] args) {

TestThreadPoolDemo testThreadPoolDemo = new TestThreadPoolDemo();

//1.通过Executors.newFixedThreadPool

ExecutorService pool = Executors.newFixedThreadPool(5);

//2.为线程中的线程分配任务

pool.submit(testThreadPoolDemo);

//3.关闭线程池:

pool.shutdown();

}

}

class TestThreadPoolDemo implements Runnable{

private int i=0;

@Override

public void run() {

while(i<=100){

System.out.println(Thread.currentThread().getName()+" : "+ i++);

}

}

}

4.1通过内部类直接实现:

public class TestThreadPool {

public static void main(String[] args) {

//1.创建线程池

ExecutorService pool = Executors.newFixedThreadPool(5);

//2.通过内部类完成对值的传递

Future future = pool.submit(new Callable() {

int sum = 0;

@Override

public Integer call() throws Exception {

for (int i = 0; i <=100 ; i++) {

sum+=i;

}

return sum;

}

});

//3.取值

try {

System.out.println(future.get());

} catch (InterruptedException e) {

e.printStackTrace();

} catch (ExecutionException e) {

e.printStackTrace();

}

//4.关闭线程池

pool.shutdown();

}

}

一、线程池:提供了一个线程队列,队列中保存这所有等待状态的线程。避免了创建与销毁额外开销,提高了响应的速度。

二、线程池的体系结构:

java.util.concurrent.Exector:负责线程的使用与调度的根接口

java.util.concurrent.Executor : 负责线程的使用与调度的根接口

|--**ExecutorService 子接口: 线程池的主要接口

|--ThreadPoolExecutor 线程池的实现类

|--ScheduledExecutorService 子接口:负责线程的调度

|--ScheduledThreadPoolExecutor :继承 ThreadPoolExecutor, 实现 ScheduledExecutorService

三、工具类:Executors

ExecutorService ==》 newFixedThreadPool() : 创建固定大小的线程池

ExecutorService ==》 newCachedThreadPool() : 缓存线程池,线程池的数量不固定,可以根据需求自动的更改数量。

ExecutorService ==》 newSingleThreadExecutor() : 创建单个线程池。线程池中只有一个线程

ScheduledExecutorService newScheduledThreadPool() : 创建固定大小的线程,可以延迟或定时的执行任务。

2. JUC简介:

在Java 5.0 提供了java.util.concurrent(简称JUC)包,在此包中添加了再并发编程中很常用的使用工具,用于定义类似于线程的自定义子系统,包括线程池,异步IO和轻量级任务框架。提供可调的、灵活的线程池。还提供了设计用于多线程上下文的Collection实现等。

3. volatile关键字 内存可见性

内存可见性(Memory Visibility)是值当前某个线程正在使用对象状态而另一个线程正在修改该状态,需要确保当一个线程修改了对象状态后,其他线程能够看到发生的状态变化。

可见性错误是指当前读操作与写操作在不用的线程中执行时,我们无法确保执行读操作的线程能实时地其他线程写入的值,有是甚至是根本不可能做的事情。

我们可以通过同步来保证对象被安全的发布。除此之外,我们也可以使用一种更加轻量级的volatile变量。

Java提供了一种稍弱的同步机制,即volatile变量,用来确保将变量的更新操作通知到其他线程,可以将volatile看做一个轻量级的锁,但是又与锁有些不同:

对于多线程,不是一种互斥关系

不能保证变量状态的“原子性操作”

volatile相对于synchronized是一种较为轻量级的同步策略。

//volatile不具备互斥性。

//volatile不能保证变量的原子性

public class TestVolatile {

public static void main(String[] args) {

TestVolatileDemo testVolatileDemo = new TestVolatileDemo();

new Thread(testVolatileDemo).start();

while(true){

if (testVolatileDemo.isFlag()){

System.out.println("----------------");

break;

}

}

}

}

class TestVolatileDemo implements Runnable{

private volatile boolean flag = false;

@Override

public void run() {

try {

Thread.sleep(200);

} catch (InterruptedException e) {

e.printStackTrace();

}

flag = true;

System.out.println("flag="+isFlag());

}

public boolean isFlag() {

return flag;

}

public void setFlag(boolean flag) {

this.flag = flag;

}

}

4. CAS算法

模拟CAS算法:

public class TestCompareAndSwap {

public static void main(String[] args) {

final CompareAndSwap cas=new CompareAndSwap();

for (int i = 0; i < 10; i++) {

new Thread(new Runnable() {

@Override

public void run() {

int expectedValue = cas.get();

boolean b = cas.compareAndSet(expectedValue,(int)(Math.random()+101));

System.out.println(b);

}

}).start();

}

}

}

class CompareAndSwap{

private int value;

//获取内存值

public synchronized int get() {

return value;

}

//比较

public synchronized int compareAndSwap(int ecpectedValue,int newValue) {

int oldValue=value;

if(oldValue == ecpectedValue) {

this.value = newValue;

}

return oldValue;

}

public synchronized boolean compareAndSet(int expectedValue, int newValue) {

return expectedValue == compareAndSwap(expectedValue, newValue);

}

}

CAS(Compare-And-Swap)是一种硬件对并发的支持,针对多处理器操作而设计的处理器中的一种特殊指令,用于管理对共享数据的并发访问。

CAS是一种无所的非阻塞算法的实现。

CAS包含了三个操作数:

需要读写的内存值V

进行比较的值A

拟写入的新值B

当且仅当V的值等于A时,CAS通过原子方式用新值B来更新V的值,否则不会执行任何操作。

原子性:

/*

* 一、i++的原子性问题:实际上是分为三个步骤,读-该-写

* 二、解决方案:原子变量:jdk1.5后java.util.concurrent.atomic包下提供了常用的原子变量

* 1.volatile 保证内存可见性。

* 2.CAS(Compare-and-swap)算法保证数据的原子性。

* CSA算法是硬件对于并发操作共享数据的支持。

* CSA包含了三个操作:内存值 V 预估值A更新值B;当且仅当V==A时,V=B,否则不做任何操作

*/

public class TestAtomicDemo {

public static void main(String[] args) {

AtomicDemo ad = new AtomicDemo();

for (int i = 0; i < 10; i++) {

new Thread(ad).start();

}

}

}

class AtomicDemo implements Runnable{

//private volatile int serialNumber=0;

private AtomicInteger serialNumber=new AtomicInteger();

@Override

public void run() {

try {

Thread.sleep(200);

} catch (InterruptedException e) {

}

System.out.println(Thread.currentThread().getName()+"="+getSerialNumber());

}

public int getSerialNumber() {

return serialNumber.getAndIncrement();

}

}

5. ConcurrentHashMap锁分段机制:

Java 5.0 在java.util.concurrent包中提供了多种并发容器类来改进同步容器的性能。

ConcurrentHashMap同步容器类是Java 5增加的一个线程安全的哈希表。对于多线程的操作,介于HashMap与HashTable之间,内部采用“锁分段”机制代替HashTable的独占锁。进而提高性能。

此包还提供了设计用于多线程上下文中的Collection实现:

ConcurrentHashMap、COncurrentSkipListMap、COncurrentSkipListSet、CopyOnWriteArrayList和CopyOnWriteArraySet。当期望许多线程访问一个给定collection时,ConcurrentHashMap通常由于同步线程的HashMap,ConcurrentSkipListMap通常优于同步的TreeMap。当企鹅昂的读书和遍历远远大于列表的更新数时,CopyOnWriteArrayList由于同步的ArrayList。

如果同一组数据,即读取,有写入的话,这样是会报错的。

/**

* 直接使用会报错:private static List list = Collections.synchronizedList(new ArrayList());

* ConcurrentModificationException

* 因为操作的是同一组数据。

*

* CopyOnWriteArrayList/CopyOnWriteArraySet:"写入并复制"

* 注意:

* 添加操作多时,效率低,因为每次添加时都会进行复制,开销非常大。并发迭代操作多时,可以选择。

*/

import java.util.ArrayList;

import java.util.Collections;

import java.util.Iterator;

import java.util.List;

import java.util.concurrent.CopyOnWriteArrayList;

public class TestCopyOnWriteArrayList {

public static void main(String[] args) {

HelloThread hThread = new HelloThread();

for (int i = 0; i < 10; i++) {

new Thread(hThread).start();

}

}

}

class HelloThread implements Runnable{

//private static List list = Collections.synchronizedList(new ArrayList());

private static CopyOnWriteArrayList list = new CopyOnWriteArrayList();

static {

list.add("AA");

list.add("BB");

list.add("CC");

}

@Override

public void run() {

// TODO Auto-generated method stub

Iterator it = list.iterator();

while (it.hasNext()) {

System.out.println(it.next());

list.add("123");

}

}

}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值