绕不过的多线程,解不开的锁

1、Runnable, Callable

1. Runnable 及 Thread
class Thread implements Runnable

2. Callable
future模式:Future对象用来存放该线程的返回值以及状态
future.isDone() // 无阻塞
future.get()      // 阻塞

ExecutorService threadPool = Executors.newFixedThreadPool(3);
 //submit方法有多重参数版本,及支持callable也能够支持runnable接口类型.
Future future = threadPool.submit(new MyCallable());
future.isDone();  // return true / false, 无阻塞
future.get();       //  return 返回值,阻塞直到该线程运行结束

2、ExecutorService, ThreadPoolExecutor

ExecutorService threadPool = null;
// threadPool = Executors.newCachedThreadPool();
// threadPool = Executors.newSingleThreadExecutor();
// threadPool = Executors.newFixedThreadPool(3);

// 以上类似的线城池创建方法,内部都是通过ThreadPoolExecutor实现的
// corePoolSize = 1      // 最多维持1个空闲核心线程数
// maximumPoolSize = 128 // 128 * 8M = 1G // 最多开启128个线程,约开销1G内存
// keepAliveTime = 60    // 60秒即每1分钟检查一次空闲线程
threadPool = new ThreadPoolExecutor(1, 128, 60L, TimeUnit.SECONDS, new SynchronousQueue<>());

3、ThreadLocal

绑定当前线程,为每个使用ThreadLocal的线程提供独立的变量副本。

实现:每个Thread都持有一个TreadLocalMap类型的变量

threadLocall.set(T value); // 操作当前Thread的TreadLocalMap,

                                        // key存放ThreadLocal, value存放目标变量

threadLocall.get();          // 返回目标变量

4、原子类(AtomicInteger、AtomicBoolean……)

// CAS无锁算法,(Compare and swap)比较与交换,是一种乐观锁机制
/**
*  Atomically sets the value to the given updated value
*  if the current value {@code ==} the expected value
/
AtomicInteger.compareAndSet(int expect, int update) //返回值为boolean

5、volatile

volatile能保证被修饰的变量对所有线程可见,因此在使用volatile修饰的变量时不会发生上下文切换和线程调度等操作。但volatile只能保证变量对各个线程的可见性,不能保证原子性,并且在线程安全的情况下加volatile会牺牲性能。

当变量被volatile关键字修饰后,线程执行引擎就会去主内存中去读取变量值,同时主内存会把改变的变量值更新到线程工作内存当中

 

6、synchronized, wait, notify

wait / notify是Object类提供的方法,即所有对象都有这两个方法。使用时注意:

1.wait和notify必须配合synchronized关键字使用

2.wait方法释放锁,notify方法不释放锁。

/**
   * 生产者生产出来的产品交给店员
   */
  public synchronized void produce() {
      if(this.product >= MAX_PRODUCT) {
          try {
              wait();  
              System.out.println("产品已满,请稍候再生产");
          } catch(InterruptedException e) {
              e.printStackTrace();
          }
          return;
      }

      this.product++;
      log.info("生产者生产第" + this.product + "个产品.");
      notifyAll();   // 通知等待区的消费者可以取出产品了
  }

  /**
   * 消费者从店员取产品
   */
  public synchronized void consume() {
      if(this.product <= MIN_PRODUCT) {
          try {
              wait(); 
              System.out.println("缺货,稍候再取");
          }  catch (InterruptedException e)  {
              e.printStackTrace();
          }
          return;
      }

      log.info("消费者取走了第" + this.product + "个产品.");
      this.product--;
      notifyAll();   // 通知等待去的生产者可以生产产品了
  }

7、ReentrantLock

可重入锁,即已经持有锁的线程可以再次持有,并且要释放对等的次数后才真正释放该锁

// 可重入锁
ReentrantLock lock = new ReentrantLock();
try {
    lock.lock(); // 加锁
    // lock.tryLock(1, TimeUnit.SECONDS); // 设置超时时间
    // lock.lockInterruptibly(); // 可打断锁
} catch (InterruptedException e) {
    e.printStackTrace();
} finally {
    lock.unlock(); // 释放锁
}
// 可重入读写锁 (两者都有lock,unlock方法。写写,写读互斥;读读不互斥)
ReentrantReadWriteLock rw = new ReentrantReadWriteLock();
ReentrantReadWriteLock.ReadLock r = rw.readLock();
ReentrantReadWriteLock.WriteLock w = rw.writeLock();

8、ConcurrentHashMap

JDK1.7:

static final class Segment<K,V> extends ReentrantLock implements Serializable

分段锁Segment,不会像 HashTable 那样不管是 put 还是 get 操作都需要做同步处理,每当一个线程占用锁访问一个 Segment 时,不会影响到其他的 Segment。

因此ConcurrentHashMap性能由于HashTable

JDK1.8:

废弃分段锁,采用CAS + synchronized + volatile

9、COW容器

CopyOnWrite容器即写时复制的容器。通俗的理解是当我们往一个容器添加元素的时候,不直接往容器添加,而是先将当前容器的引用指向新的容器。这样做的好处是我们可以对CopyOnWrite容器进行并发的读,而不需要加锁,因为当前容器不会添加任何元素。所以CopyOnWrite容器也是一种读写分离的思想,读和写在不同的容器。

当第一个写请求被容器收到后,容器复制出一个副本出来,线程一去这个副本修改数据,其它线程也要修改容器数据,那就只能在副本容器外排队等候,因为容器的写操作是加锁的。

CopyOnWrite容器特别适用于读多写少的场景

 

 

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值