并发
并行
wait
sleep
管程
用户线程
守护进程
Lock接口
java中的sync关键字 同步锁
多线程编程的步骤:
1、创建一个资源类,在资源类创建属性和操作方法
空调资源类,空调有操作(制冷,制热) 追求高内聚,低耦合
2、在资源类的操作方法上
判断、干活、通知
3、创建多个线程、调用资源类和操作方法
4、防止虚假唤醒问题,判断在放在while()中
例子:3个售票员 卖出30张票
票是资源,票的数量是属性,卖票的方法
售票员就是3个线程
创建线程的方式:
继承Thread类、实现Runnalbe接口(经常用)、使用Callable接口、线程池
Callable接口:
import java.util.concurrent.ExecutionException;
import java.util.concurrent.FutureTask;
/**
* @Author: suny
* @Date: 2021/09/03 上午11:59
* @Description:
*/
public class callableTest {
public static void main(String[] args) {
FutureTask<Integer> futureTask1 = new FutureTask<>(() -> {
System.out.println(Thread.currentThread().getName() + "come in callable");
return 1024;
});
new Thread(futureTask1,"aa").start();
try {
System.out.println(futureTask1.get());
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
}
}
}
例子:
两个线程 ,实现对一个初始值0的变量 ,一个对其值+1,另一个对其值-1
可重入锁:厕所(每个人进去都会上锁,粗来解锁) Lock接口
Lock的操作更广,Lock不是java语言内置的
Lock和synchronized的区别:
JUC3大辅助类:
减少计数CountDownLatch(6个同学都离开后班长锁门)
import java.util.concurrent.CountDownLatch;
/**
* @Author: suny
* @Date: 2021/09/05 下午9:01
* @Description: 减少计数CyclicBarrier
*/
public class CountDownLatchTest {
//有六个同学陆续离开教室后,班长锁门
public static void main(String[] args) throws InterruptedException {
//创建CountDownLatch对象,设置初始值
CountDownLatch countDownLatch = new CountDownLatch(6);
for (int i = 1; i <= 6; i++) {
new Thread(() -> {
System.out.println(Thread.currentThread().getName() + "离开了教室");
},String.valueOf(i)).start();
countDownLatch.countDown();
System.out.println(countDownLatch.getCount());
}
countDownLatch.await();
System.out.println(Thread.currentThread().getName() + "班长锁门了");
}
}
一个或者多个线程调用await方法 让线程阻塞,其他线程
循环栅栏 (集齐7颗龙珠召唤神龙)
import java.util.concurrent.BrokenBarrierException;
import java.util.concurrent.CyclicBarrier;
/**
* @Author: suny
* @Date: 2021/09/05 下午9:15
* @Description: 收集全7颗龙珠可以召唤神龙
*/
public class CyclicBarrierTest {
private static final int NUMBER = 7;
public static void main(String[] args) {
CyclicBarrier cyclicBarrier = new CyclicBarrier(NUMBER,() -> {
System.out.println("集齐龙珠召唤神龙");
});
for (int i = 1; i < 8; i++) {
new Thread(() ->{
try {
try {
System.out.println(Thread.currentThread().getName() + "星收集到了");
//等待
cyclicBarrier.await();
} catch (BrokenBarrierException e) {
e.printStackTrace();
}
} catch (InterruptedException e) {
e.printStackTrace();
}
},String.valueOf(i)).start();
}
}
}
信号灯(6辆车停在3个停车位)
/**
* @Author: suny
* @Date: 2021/09/05 下午9:52
* @Description:
*
* 3个车位,6辆汽车
*
*/
public class SemaphoreTest {
public static void main(String[] args) {
Semaphore semaphore = new Semaphore(3);
for (int i = 1; i <= 6; i++) {
new Thread(() -> {
try {
//获得许可
semaphore.acquire();
System.out.println(Thread.currentThread().getName() + "抢到了!");
//设置随机停车时间
TimeUnit.SECONDS.sleep(new Random().nextInt(5));
System.out.println(Thread.currentThread().getName() + "*****离开了!");
} catch (Exception e) {
e.printStackTrace();
} finally {
//释放许可
semaphore.release();
}
},String.valueOf(i)).start();
}
}
}
悲观锁:
上锁,解锁后,别人才能操作。上锁-解锁,不能并发,效率低。
乐观锁:
乐观锁,都能操作,都会得到一个版本号,修改后,要改版本号,另一个人提交之前要进行比较,
如果不一致,就会失败,谁先提交,修改版本号,就事务成功。
表锁:(没有死锁)
只操作一行记录,但是把整个表都锁住了
行锁:(会发生死锁)
只对要操作的那一行上锁
读锁:共享锁,会有死锁
(读的时候不能写)
写锁:独占锁, 会有死锁
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.ReadWriteLock;
import java.util.concurrent.locks.ReentrantReadWriteLock;
/**
* @Author: suny
* @Date: 2021/09/05 下午10:32
* @Description: 没有写完,就开始读,会存在问题的 ----可以通过读写锁进行解决
* 写是独占锁 读是共享锁
*/
/**
资源类
*/
class MyCache {
//创建map集合
//volatile 保证可见性,禁止重排序
private volatile Map<String,Object> map = new HashMap<>();
//创建读写锁对象
private ReadWriteLock rwLock = new ReentrantReadWriteLock();
//存数据
public void putData(String key, Object value){
//添加锁
rwLock.writeLock().lock();
try {
System.out.println(Thread.currentThread().getName() + "正在写操作" + key);
//暂停一会
TimeUnit.MICROSECONDS.sleep(300);
map.put(key, value);
System.out.println(Thread.currentThread().getName() + "写操作完成" + key);
} catch (InterruptedException e) {
e.printStackTrace();
}finally {
//释放写锁
rwLock.writeLock().unlock();
}
}
//读数据
public Object getData(String key){
Object res = null;
//添加读锁
rwLock.readLock().lock();
try {
System.out.println(Thread.currentThread().getName() + "正在读操作" + key);
//暂停一会
TimeUnit.MICROSECONDS.sleep(300);
res = map.get(key);
System.out.println(Thread.currentThread().getName() + "读操作完成" + key);
} catch (InterruptedException e) {
e.printStackTrace();
}finally {
//释放锁
rwLock.readLock().unlock();
}
return res;
}
}
public class ReadWriteTest {
public static void main(String[] args) throws InterruptedException {
MyCache myCache = new MyCache();
//创建线程放数据
for (int i = 1; i < 6; i++) {
final int num = i ;
new Thread(() -> {
//内部类访问外部数据的时候只能访问常量(final修饰的变量)
myCache.putData(num + "",num + "");
},String.valueOf(i)).start();
}
TimeUnit.MICROSECONDS.sleep(300);
//创建线程取数据
for (int i = 1; i < 6; i++) {
final int num = i ;
new Thread(() -> {
//内部类访问外部数据的时候只能访问常量(final修饰的变量)
myCache.getData(num + "");
},String.valueOf(i)).start();
}
}
}