- 代码Github下载地址
- synchronized(常用)
- Lock
- lock,unlock
- trylock
- ReadAndWriteLock(读写锁)
- Atomic(i++操作)
- LongAdder(Atomic的优化)
- CountdownLatch(门闩)
- Exchanger(线程交换数据)
- Locksupport(类似于lock)
- Phaser (过程中,锁部分线程)
- CyclicBarrier(循环栅栏)
- Semaphore(限流)
- Unsafe(操作内存实现线程安全-不推荐)
代码Github下载地址
点击跳转
https://github.com/MaBo2420935619/ThreadLocksynchronized(常用)
使用JDK5引进的CAS自旋之外,还增加了自适应的CAS自旋、锁消除、锁粗化、偏向锁、轻量级锁这些优化策略。由于此关键字的优化使得性能极大提高,同时语义清晰、操作简单、无需手动关闭,所以推荐在允许的情况下尽量使用此关键字,同时在性能上此关键字还有优化的空间。
锁主要存在四种状态,依次是:无锁状态、偏向锁状态、轻量级锁状态、重量级锁状态,锁可以从偏向锁升级到轻量级锁,再升级的重量级锁。但是锁的升级是单向的,也就是说只能从低到高升级,不会出现锁的降级。
public class RunnableTest implements Runnable{
private final static int Max=10000;
private final static int Number=100000;
private Object object=new Object();
private int a=0;
public int getA() {
return a;
}
public void setA(int a) {
this.a = a;
}
@Override
public void run() {
synchronized (object){
for (int i = 0; i < Number; i++) {
a++;
}
}
}
public static void main(String[] args) {
long start = System.currentTimeMillis();
RunnableTest test=new RunnableTest();
for (int i = 0; i < Max; i++) {
Thread thread = new Thread(test::run);
thread.start();
try {
thread.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
Thread threadX = new Thread(new Runnable() {
public void run() {
System.out.println(test.getA());
long end = System.currentTimeMillis();
System.out.println((end-start)+"ms");
}
});
threadX.start();
}
}
Lock
Lock,必须主动去释放锁,并且在发生异常时,不会自动释放锁。因此一般来说,使用Lock必须在try{}catch{}块中进行,并且将释放锁的操作放在finally块中进行,以保证锁一定被被释放,防止死锁的发生。
lock,unlockpackage lock;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
public class TestReentrantLock implements Runnable {
private Lock lock = new ReentrantLock();
int a=0;
public int getA() {
return a;
}
public static void main(String[] args) throws InterruptedException {
long start = System.currentTimeMillis();
TestReentrantLock test = new TestReentrantLock();
for (int i = 0; i < 1000; i++) {
Thread thread = new Thread(test);
thread.start();
thread.join();
}
Thread threadX = new Thread(() -> {
System.out.println(test.getA());
long end = System.currentTimeMillis();
System.out.println((end-start)+"ms");
});
threadX.start();
}
@Override
public void run() {
lock.lock();
try {
for (int i = 0; i < 100000; i++) {
a++;
}
}finally {
lock.unlock();
}
}
}
trylock
package lock;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
public class TestTryLock {
private static int a=0;
public static int getA() {
return a;
}
public static void setA(int a) {
TestTryLock.a = a;
}
private static Lock lock=new ReentrantLock();;
public static void main(String[] args) throws InterruptedException {
long start = System.currentTimeMillis();
TestTryLock test=new TestTryLock();
for (int i = 0; i < 3; i++) {
Thread thread = new Thread(test::add);
thread.start();
thread.join();
}
Thread threadX = new Thread(new Runnable() {
public void run() {
System.out.println(test.getA());
long end = System.currentTimeMillis();
System.out.println((end-start)+"ms");
}
});
threadX.start();
}
public void add(){
try {
lock.tryLock(1, TimeUnit.SECONDS);
a++;
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
finally {
lock.unlock();
}
}
}
ReadAndWriteLock(读写锁)
ReentrantReadWriteLock允许多个读线程同时访问,但不允许写线程和读线程、写线程和写线程同时访问。相对于排他锁,提高了并发性。在实际应用中,大部分情况下对共享数据(如缓存)的访问都是读操作远多于写操作,这时ReentrantReadWriteLock能够提供比排他锁更好的并发性和吞吐量。
读写锁内部维护了两个锁,一个用于读操作,一个用于写操作。所有 ReadWriteLock实现都必须保证 writeLock操作的内存同步效果也要保持与相关 readLock的联系。也就是说,成功获取读锁的线程会看到写入锁之前版本所做的所有更新。
ReentrantReadWriteLock支持以下功能:
1)支持公平和非公平的获取锁的方式;
2)支持可重入。读线程在获取了读锁后还可以获取读锁;写线程在获取了写锁之后既可以再次获取写锁又可以获取读锁;
3)还允许从写入锁降级为读取锁,其实现方式是:先获取写入锁,然后获取读取锁,最后释放写入锁。但是,从读取锁升级到写入锁是不允许的;
4)读取锁和写入锁都支持锁获取期间的中断;
5)Condition支持。仅写入锁提供了一个 Conditon 实现;读取锁不支持 Conditon ,readLock().newCondition() 会抛出 UnsupportedOperationException。
package readAndWriteLock;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReadWriteLock;
import java.util.concurrent.locks.ReentrantReadWriteLock;
public class ReadAndWriteLockTest {
static ReadWriteLock readWriteLock=new ReentrantReadWriteLock();
static Lock read=readWriteLock.readLock();
static Lock write=readWriteLock.writeLock();
public static void main(String[] args) {
for (int i = 0; i < 10; i++) {
new Thread(() -> {
try {
read.lock();
Thread.sleep(1000);
System.out.println("我在读");
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
read.unlock();
}
}).start();
}
for (int i = 0; i < 3; i++) {
new Thread(() -> {
try {
write.lock();
Thread.sleep(1000);
System.out.println("我在写");
} catch (Exception e) {
e.printStackTrace();
} finally {
write.unlock();
}
}).start();
}
}
}
Atomic(i++操作)
原子更新类,利用CAS(CompareAndSwap)实现无锁操作,占用CPU资源。依赖CPU的原语实现。
AtomicBoolean:原子更新布尔类型。
AtomicInteger:原子更新整型。
AtomicLong:原子更新长整型。
AtomicInteger的常用方法如下:
- int addAndGet(int delta):以原子方式将输入的数值与实例中的值(AtomicInteger里的value)相加,并返回结果
- boolean compareAndSet(int expect, int update) :如果输入的数值等于预期值,则以原子方式将该值设置为输入的值。
- int getAndIncrement():以原子方式将当前值加1,注意:这里返回的是自增前的值。
- void lazySet(int newValue):最终会设置成newValue,使用lazySet设置值后,可能导致其他线程在之后的一小段时间内还是可以读到旧的值
- int getAndSet(int newValue):以原子方式设置为newValue的值,并返回旧值。
package atomic;
import java.util.concurrent.atomic.AtomicInteger;
public class AtomicIntegerTest implements Runnable {
private final static int Max=10000;
private final static int Number=100000;
AtomicInteger atomicInteger=new AtomicInteger(0);
public AtomicInteger getAtomicInteger() {
return atomicInteger;
}
public void setAtomicInteger(AtomicInteger atomicInteger) {
this.atomicInteger = atomicInteger;
}
@Override
public void run() {
for (int i = 0; i < Number; i++) {
atomicInteger.incrementAndGet();
}
}
public static void main(String[] args) {
long start = System.currentTimeMillis();
AtomicIntegerTest test=new AtomicIntegerTest();
for (int i = 0; i < Max; i++) {
Thread thread = new Thread(test::run);
thread.start();
try {
thread.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
Thread threadX = new Thread(new Runnable() {
public void run() {
System.out.println(test.getAtomicInteger());
long end = System.currentTimeMillis();
System.out.println((end-start)+"ms");
}
});
threadX.start();
}
}
LongAdder(Atomic的优化)
LongAdder是一种以空间换时间的解决方案。其内部维护了一个值base,和一个cell数组,当线程写base有冲突时,将其写入数组的一个cell中。将base和所有cell中的值求和就得到最终LongAdder的值了。
package LongAdder;
import java.util.concurrent.atomic.LongAdder;
public class LongAdderTest implements Runnable {
private final static int Max=1000;
private final static int Number=100000;
LongAdder longAdder = new LongAdder();
public LongAdder getLongAdder() {
return longAdder;
}
public void setLongAdder(LongAdder longAdder) {
this.longAdder = longAdder;
}
@Override
public void run() {
for (int i = 0; i < Number; i++) {
longAdder.increment();
}
}
public static void main(String[] args) throws InterruptedException {
long start = System.currentTimeMillis();
LongAdderTest test=new LongAdderTest();
for (int i = 0; i < Max; i++) {
Thread thread = new Thread(test::run);
thread.start();
thread.join();
}
Thread threadX = new Thread(new Runnable() {
public void run() {
System.out.println(test.getLongAdder());
long end = System.currentTimeMillis();
System.out.println((end-start)+"ms");
}
});
threadX.start();
}
}
CountdownLatch(门闩)
CountDownLatch是一个同步工具类,用来协调多个线程之间的同步,或者说起到线程之间的通信(而不是用作互斥的作用)。
CountDownLatch能够使一个线程在等待另外一些线程完成各自工作之后,再继续执行。使用一个计数器进行实现。计数器初始值为线程的数量。当每一个线程完成自己任务后,计数器的值就会减一。当计数器的值为0时,表示所有的线程都已经完成一些任务,然后在CountDownLatch上等待的线程就可以恢复执行接下来的任务。
package countdownLatch;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
public class CountdownLatchTest {
static int a=0;
public static void main(String[] args) throws InterruptedException {
Lock lock=new ReentrantLock(true);
Thread threads[]=new Thread[100];
CountDownLatch countDownLatch=new CountDownLatch(threads.length);
for (Thread t : threads) {
t=new Thread(() -> {
try {
lock.lock();
a++;
countDownLatch.countDown();
} finally {
lock.unlock();
}
});
t.start();
}
countDownLatch.await();
System.out.println(a);
}
}
Exchanger(线程交换数据)
Exchanger(交换者)是一个用于线程间协作的工具类。Exchanger用于进行线程间的数据交换。它提供一个同步点,在这个同步点两个线程可以交换彼此的数据。这两个线程通过exchange方法交换数据, 如果第一个线程先执行exchange方法,它会一直等待第二个线程也执行exchange,当两个线程都到达同步点时,这两个线程就可以交换数据,将本线程生产出来的数据传递给对方。因此使用Exchanger的重点是成对的线程使用exchange()方法,当有一对线程达到了同步点,就会进行交换数据。因此该工具类的线程对象是成对的。
Exchanger类提供了两个方法,String exchange(V x):用于交换,启动交换并等待另一个线程调用exchange;String exchange(V x,long timeout,TimeUnit unit):用于交换,启动交换并等待另一个线程调用exchange,并且设置最大等待时间,当等待时间超过timeout便停止等待。
package exchanger;
import java.util.concurrent.Exchanger;
public class ExchangerTest {
static Exchanger exchanger=new Exchanger<>();
static class Show implements Runnable{
private String name;
public Show(String name) {
this.name = name;
}
@Override
public void run() {
try {
name= exchanger.exchange(name);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName());
System.out.println(name);
}
}
public static void main(String[] args) {
Exchanger exchanger=new Exchanger<>();
Thread thread1=new Thread(new Show("1"),"t1");
Thread thread2=new Thread(new Show("2"),"t2");
thread1.start();
thread2.start();
}
}
Locksupport(类似于lock)
- park和unpark可以实现类似wait和notify的功能,但是并不和wait和notify交叉,也就是说unpark不会对wait起作用,notify也不会对park起作用。
- park和unpark的使用不会出现死锁的情况
- blocker的作用是在dump线程的时候看到阻塞对象的信息
package locksupport;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.LockSupport;
public class LocksupportTest {
public static void main(String[] args) throws InterruptedException {
Thread thread = new Thread(new Runnable() {
@Override
public void run() {
for (int i = 0; i < 10; i++) {
if (i ==3) {
LockSupport.park();
}
System.out.println(i);
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
});
thread.start();
TimeUnit.SECONDS.sleep(6);
LockSupport.unpark(thread);
}
}
Phaser (过程中,锁部分线程)
Phaser类似于CountdownLatch,但是Phaser可以有多个周期。
package phaser;
import java.util.concurrent.Phaser;
public class PhaserTest {
public static void main(String[] args) {
WorkPhaser workPhaser=new WorkPhaser();
workPhaser.bulkRegister(3);
for (int i = 1; i < 4; i++) {
Person person = new Person(workPhaser, String.valueOf(i));
Thread thread=new Thread(person,String.valueOf(i));
thread.start();
}
}
private static class Person implements Runnable{
private Phaser phaser;
private String name;
public Person(Phaser phaser, String name) {
this.phaser = phaser;
this.name = name;
}
@Override
public void run() {
work1();
work2();
work3();
}
private void work1(){
String playerName = Thread.currentThread().getName();
System.out.println(playerName+" 吃");
phaser.arriveAndAwaitAdvance();
}
private void work2(){
String playerName = Thread.currentThread().getName();
if (playerName.equals("1")||playerName.equals("2")){
System.out.println(playerName+" 上厕所");
phaser.arriveAndAwaitAdvance();
}
else {
System.out.println(playerName+" 不上厕所");
phaser.arriveAndDeregister();
}
}
private void work3() {
String playerName = Thread.currentThread().getName();
if (playerName.equals("2")||playerName.equals("3")){
System.out.println(playerName+" 回家");
phaser.arriveAndAwaitAdvance();
}
else {
System.out.println(playerName+" 不回家");
phaser.arriveAndDeregister();
}
}
}
private static class WorkPhaser extends Phaser {
@Override
protected boolean onAdvance(int phase, int registeredParties) {
switch (phase) {
case 0:
System.out.println("所有人都到吃"+registeredParties);
return false;
case 1:
System.out.println("1和2一起上厕所"+registeredParties);
return false;
case 2:
System.out.println("2和3一起回家"+registeredParties);
return true;
default:
return true;
}
}
}
}
CyclicBarrier(循环栅栏)
作用就是会让所有线程都等待完成后才会执行
package cyclicBarrier;
import java.util.concurrent.CyclicBarrier;
public class CyclicBarrierTest {
// 自定义工作线程
private static class Worker implements Runnable {
private static CyclicBarrier cyclicBarrier=new CyclicBarrier(5);
@Override
public void run() {
try {
System.out.println(Thread.currentThread().getName() + "开始等待其他线程");
cyclicBarrier.await();
System.out.println(Thread.currentThread().getName() + "执行");
} catch (Exception e) {
e.printStackTrace();
}
}
}
public static void main(String[] args) {
for (int i = 0; i < 100; i++) {
System.out.println("创建工作线程" + i);
Thread thread=new Thread(new Worker());
thread.start();
}
}
}
Semaphore(限流)
限制线程可以同时运行的数量
package semaphore;
import java.util.concurrent.Semaphore;
public class SemaphoreTest {
public static void main(String[] args) {
Semaphore semaphore=new Semaphore(2);
for (int i = 0; i < 6; i++) {
new Thread(new Runnable() {
@Override
public void run() {
try {
semaphore.acquire();
for (int j = 0; j < 2; j++) {
Thread.sleep(1000);
System.out.println(Thread.currentThread().getName());
}
} catch (InterruptedException e) {
e.printStackTrace();
}
finally {
semaphore.release();
}
}
}).start();
}
}
}
Unsafe(操作内存实现线程安全-不推荐)
较为底层的一中线程锁的方法,不安全。
package myLock;
import sun.misc.Unsafe;
import java.lang.reflect.Field;
public class TestUnsafe {
volatile int n = 0;
private static Unsafe unsafe = null;
private static long fieldOffset;
static {
Field unsafe1 = null;//获取Unsafe的theUnsafe属性
try {
unsafe1 = Unsafe.class.getDeclaredField("theUnsafe");
unsafe1.setAccessible(true);
unsafe = (Unsafe) unsafe1.get(null);//unsafe实例对象
Field n1 = TestUnsafe.class.getDeclaredField("n");
fieldOffset = unsafe.objectFieldOffset(n1);//获取偏移量
} catch (NoSuchFieldException | IllegalAccessException e) {
e.printStackTrace();
}
}
public void add() {
int intVolatile = unsafe.getIntVolatile(this, fieldOffset);//获取值
for (; ; ) {//防止伪唤醒
unsafe.compareAndSwapInt(this, fieldOffset, intVolatile, intVolatile + 1);// add +1
break;
}
}
public static void main(String[] args) {
TestUnsafe testUnsafe = new TestUnsafe();
for (int i = 0; i < 100; i++) {//创建6个线程实现
new Thread(() -> {
testUnsafe.add();
}).start();
}
try {
Thread.sleep(6000L);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(testUnsafe.n);
}
}



