详细看我这一篇博客的介绍https://blog.csdn.net/oldshaui/article/details/89342858
可以看我的博客:https://blog.csdn.net/oldshaui/article/details/89432726
1.使用jdk1.0提供的vector(基本不用的方法)
2.使用Collections.synchronizedList(传入一个线程不安全的集合)(把list转换为一个安全的集合)
3.使用CopyOnWriteArrayList
介绍下CopyOnWriteArrayList
/**
* 笔记
* 写时复制 copyOnWrite 容器即写时复制的容器 往容器添加元素的时候,不直接往当前容器object[]添加,而是先将当前容器object[]进行
* copy 复制出一个新的object[] newElements 然后向新容器object[] newElements 里面添加元素 添加元素后,
* 再将原容器的引用指向新的容器 setArray(newElements);
* 这样的好处是可以对copyOnWrite容器进行并发的读,而不需要加锁 因为当前容器不会添加任何容器.所以copyOnwrite容器也是一种
* 读写分离的思想,读和写不同的容器.
* public boolean add(E e) {
* final ReentrantLock lock = this.lock;
* lock.lock();
* try {
* Object[] elements = getArray();
* int len = elements.length;
* Object[] newElements = Arrays.copyOf(elements, len + 1);
* newElements[len] = e;
* setArray(newElements);
* return true;
* } finally {
* lock.unlock();
* }
* }
* @param args
*/
1.可重入锁
package cn.carryshuai.one.多线程.java的几种锁.可重入锁;
class Phone{
public synchronized void sendSms() throws Exception{
System.out.println(Thread.currentThread().getName()+"\tsendSms");
sendEmail();
}
public synchronized void sendEmail() throws Exception{
System.out.println(Thread.currentThread().getName()+"\tsendEmail");
}
}
/**
* Description:
* 可重入锁(也叫做递归锁)
* 指的是同一先生外层函数获得锁后,内层敌对函数任然能获取该锁的代码
* 在同一线程外外层方法获取锁的时候,在进入内层方法会自动获取锁
*
* 也就是说,线程可以进入任何一个它已经标记的锁所同步的代码块
*
* @author [email protected]
* @date 2019-06-10 23:36
**/
public class ReenterLockDemo {
/**
* t1 sendSms
* t1 sendEmail
* t2 sendSms
* t2 sendEmail
* @param args
*/
public static void main(String[] args) {
Phone phone = new Phone();
new Thread(()->{
try {
phone.sendSms();
} catch (Exception e) {
e.printStackTrace();
}
},"t1").start();
new Thread(()->{
try {
phone.sendSms();
} catch (Exception e) {
e.printStackTrace();
}
},"t2").start();
}
}
//执行结果
t1 sendSms
t1 sendEmail
t2 sendSms
t2 sendEmail
2.非/公平锁
3.自旋锁
package cn.carryshuai.one.多线程.java的几种锁.自旋锁;
import java.util.concurrent.atomic.AtomicReference;
/**
* 自旋锁:指定尝试获取锁的线程不会立即堵塞,而是采用循环的方式尝试获取锁,
* 这样的好处就是减少了线程上下文的切换的消耗,缺点是循环会消耗cpu
*/
public class OptionalDemo {
private AtomicReference atomicReference = new AtomicReference<>();
public void lock(){
System.out.println(Thread.currentThread() + " coming...");
//如果期望是空的话,就设置为当前线程,跳出while循环
while (!atomicReference.compareAndSet(null,Thread.currentThread())){
}
}
public void unlock(){
Thread thread = Thread.currentThread();
atomicReference.compareAndSet(thread,null);
System.out.println(thread+"unlock;;;;;");
}
public static void main(String[] args) throws InterruptedException {
OptionalDemo optionalDemo = new OptionalDemo();
new Thread(()->{
optionalDemo.lock();
try {
Thread.sleep(1000);
}catch (Exception e){
}
System.out.println("hahah");
optionalDemo.unlock();
}).start();
Thread.sleep(1000);
new Thread(() -> {
optionalDemo.lock();
System.out.println("hehehe");
optionalDemo.unlock();
}).start();
}
}
4.读写锁
package cn.carryshuai.one.多线程.java的几种锁.读写锁;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.locks.ReentrantReadWriteLock;
public class ReentrantReadWriteLockDemo {
public static void main(String[] args){
Mycache mycache = new Mycache();
for (int i = 0; i < 5; i++) {
final int temp = i;
new Thread(()->{
try {
mycache.put(temp+"",temp+"");
} catch (Exception e) {
e.printStackTrace();
}
}).start();
}
for (int i = 0; i < 5; i++) {
final int temp = i;
new Thread(()->{
//读取数据
try {
mycache.get(temp+"");
} catch (Exception e) {
e.printStackTrace();
}
}).start();
}
}
}
//一个缓存类
class Mycache{
private volatile Map map = new HashMap<>();
//一个读写锁
private ReentrantReadWriteLock reentrantReadWriteLock = new ReentrantReadWriteLock();
//提供一个写的操作方法
public void put(String key,Object value) throws Exception {
//添加写锁
ReentrantReadWriteLock.WriteLock writeLock = reentrantReadWriteLock.writeLock();
try {
writeLock.lock();
System.out.println(Thread.currentThread().getName()+"正在写入:"+key);
//模拟睡眠
Thread.sleep(1000);
map.put(key,value);
System.out.println(Thread.currentThread().getName()+"写入完成---");
}finally {
writeLock.unlock();
}
}
//提供一个读取的方法
public void get(String key) throws Exception {
//添加一个读锁
ReentrantReadWriteLock.ReadLock readLock = reentrantReadWriteLock.readLock();
try {
readLock.lock();
System.out.println(Thread.currentThread().getName()+"正在读取---");
//模拟睡眠
Thread.sleep(1000);
Object res = map.get(key);
System.out.println(Thread.currentThread().getName() + " 读取完成,读取结果是 " + res);
}finally {
readLock.unlock();
}
}
}
让一些线程堵塞直到另一个线程完成一系列操作后才被唤醒。CountDownLatch 主要有两个方法,当一个或多个线程调用 await 方法时,调用线程会被堵塞,其他线程调用 countDown 方法会将计数减一(调用 countDown 方法的线程不会堵塞),当计数其值变为零时,因调用 await 方法被堵塞的线程会被唤醒,继续执行。
假设我们有这么一个场景,教室里有班长和其他6个人在教室上自习,怎么保证班长等其他6个人都走出教室在把教室门给关掉。
public class CountDownLanchDemo {
public static void main(String[] args) {
for (int i = 0; i < 6; i++) {
new Thread(() -> {
System.out.println(Thread.currentThread().getName() + " 离开了教室...");
}, String.valueOf(i)).start();
}
System.out.println("班长把门给关了,离开了教室...");
}
}
CyclicBarrier
举个集齐七龙珠,召唤神龙的例子
public class CyclicBarrierDemo {
public static void main(String[] args) {
CyclicBarrier cyclicBarrier=new CyclicBarrier(7,()->{
System.out.println("召唤神龙");
});
for (int i = 1; i <=7; i++) {
final int temp = i;
new Thread(()->{
System.out.println(Thread.currentThread().getName()+"\t 收集到第"+ temp +"颗龙珠");
try {
cyclicBarrier.await();
} catch (InterruptedException e) {
e.printStackTrace();
} catch (BrokenBarrierException e) {
e.printStackTrace();
}
},String.valueOf(i)).start();
}
}
}
Semaphore
举个抢车位的例子
/**
* Description
*
* @author [email protected]
* @version 1.0
* @date 2019-04-13 11:08
**/
public class SemaphoreDemo {
public static void main(String[] args) {
//模拟3个停车位
Semaphore semaphore = new Semaphore(3);
//模拟6部汽车
for (int i = 1; i <= 6; i++) {
new Thread(() -> {
try {
//抢到资源
semaphore.acquire();
System.out.println(Thread.currentThread().getName() + "\t抢到车位");
try {
TimeUnit.SECONDS.sleep(3);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + "\t 停3秒离开车位");
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
//释放资源
semaphore.release();
}
}, String.valueOf(i)).start();
}
}
}
7.阻塞队列
阻塞队列的好处
核心方法:
8.线程池
线程池的好处:
线程池的七大参数:
线程池工作原理: