标签:死锁 ade 基础 releases 种类 als 单位 The actor
在 Java 5.0 提供了 java.util.concurrent(简称 JUC )包,在此包中增加了在并发编程中很常用的实用工具类,用于定义类似于线程的自定义子系统,包括线程池、异步 IO 和轻量级任务框架。
进入时,执行 monitorenter,将计数器 +1,释放锁 monitorexit 时,计数器-1; 当一个线程判断到计数器为 0 时,则当前锁空闲,可以占用;反之,当前线程进入等待状态。
Synchronized 是在加锁,加对象锁。
对象锁是一种重量锁(monitor),synchronized 的锁机制会根据线程竞争情况在运行时会有偏向锁(单一线程)、轻量锁(多个线程访问 synchronized 区域)、对象锁(重量锁,多个线程存在竞争的情况)、自旋锁等。 该关键字是一个几种锁的封装。
定义:volatile 是一个类型修饰符。volatile 的作用是作为指令关键字,确保本条指令不会因编译器的优化而省略。
当使用 ThreadLocal 维护变量时,其为每个使用该变量的线程提供独立的变量副本,所以每一个线程都可以独立的改变自己的副本,而不会影响其他线程对应的副本。
ThreadLocal 内部实现机制:
java.util.concurrent.ThreadPoolExecutor 类就是一个线程池。客户端调用 ThreadPoolExecutor.submit(Runnable task) 提交任务,线程池内部维护的工作者线程的数量就是该线程池的线程池大小,有 3 种形态:
形态解析:
对于核心的几个线程池,无论是 newFixedThreadPool() 方法,newSingleThreadExecutor() 还是 newCachedThreadPool() 方法,虽然看起来创建的线程有着完全不同的功能特点,但其实内部实现均使用了 ThreadPoolExecutor 实现,其实都只是 ThreadPoolExecutor 类的封装。
为何 ThreadPoolExecutor 有如此强大的功能呢?我们可以来看一下 ThreadPoolExecutor 最重要的构造函数:
public ThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue<Runnable> workQueue, ThreadFactory threadFactory, RejectedExecutionHandler handler)
函数的参数含义如下:
可以使基本数据类型以原子的方式实现自增自减等操作。
对于原子操作类,最大的特点是在多线程并发操作同一个资源的情况下,使用Lock-Free算法来替代锁,这样开销小、速度快,对于原子操作类是采用原子操作指令实现的,从而可以保证操作的原子性。什么是原子性?比如一个操作i++;实际上这是三个原子操作,先把i的值读取、然后修改(+1)、最后写入给i。所以使用Atomic原子类操作数,比如:i++;那么它会在这步操作都完成情况下才允许其它线程再对它进行操作,而这个实现则是通过Lock-Free+原子操作指令来确定的 。
用法:
public class Counter { private AtomicInteger count = new AtomicInteger(); public int getCount() { return count.get(); } public void increment() { count.incrementAndGet(); } }
继承方式:
实现方式:
Java 中的线程可以有自己的优先级。优先极高的线程在竞争资源时会更有优势,更可能抢占资源,当然,这只是一个概率问题。如果运行不好,高优先级线程可能也会抢占失败。
由于线程的优先级调度和底层操作系统有密切的关系,在各个平台上表现不一,并且这种优先级产生的后果也可能不容易预测,无法精准控制,比如一个低优先级的线程可能一直抢占不到资源,从而始终无法运行,而产生饥饿(虽然优先级低,但是也不能饿死它啊)。因此,在要求严格的场合,还是需要自己在应用层解决线程调度的问题。
在 Java 中,使用 1 到 10 表示线程优先级,一般可以使用内置的三个静态标量表示:
数字越大则优先级越高,但有效范围在 1 到 10 之间,默认的优先级为 5 。
例:
//被volatile修饰的变量发生修改时,所有使用该变量的线程都会停止使用缓存中的变量,同时停止工作去主存中获取最新的volatile变量值(轻量的锁) private static volatile Boolean stop = false; public static void main(String args[]) throws InterruptedException { //新建立一个线程 Thread testThread = new Thread() { @Override public void run() { System.out.println(); int i = 1; //不断的对i进行自增操作 while (!stop) { i++; } System.out.println("Thread stop i=" + i); } }; //启动该线程 testThread.start(); //休眠一秒 Thread.sleep(1000); //主线程中将stop置为true stop = true; System.out.println(Thread.currentThread() + "now, in main thread stop is: " + stop); testThread.join(); }
忙循环就是程序员用循环让一个线程等待,不像传统方法 wait(),sleep() 或yield() 它们都放弃了 CPU 控制权,而忙循环不会放弃 CPU,它就是在运行一个空循环。这么做的目的是为了保留 CPU 缓存。
在多核系统中,一个等待线程醒来的时候可能会在另一个内核运行,这样会重建缓存,为了避免重建缓存和减少等待重建的时间就可以使用它了。
wait() 方法应该在循环调用,因为当线程获取到 CPU 开始执行的时候,其他条件可能还没有满足(此时用if判断可能会有问题),所以在处理前,循环检测条件是否满足会更好。下面是一段标准的使用 wait 和 notify 方法的代码:
// The standard idiom for using the wait method synchronized (obj) { while (condition does not hold) obj.wait(); // (Releases lock, and reacquires on wakeup) ... // Perform action appropriate to condition }
伪共享是多线程系统(每个处理器有自己的局部缓存)中一个众所周知的性能问题。伪共享发生在不同处理器的上的线程对变量的修改依赖于相同的缓存行,如下图所示:
伪共享问题很难被发现,因为线程可能访问完全不同的全局变量,内存中却碰巧在很相近的位置上。如其他诸多的并发问题,避免伪共享的最基本方式是仔细审查代码,根据缓存行来调整你的数据结构。
标签:死锁 ade 基础 releases 种类 als 单位 The actor
原文地址:https://www.cnblogs.com/riches/p/11773441.html