①并发—同一个对象被多个线程同时操作
②线程同步安全性形成条件:队列+锁
③为了保证数据在方法中被访问时的正确性,在访问时加入锁机制(synchronized)
④为了保证安全性,会导致性能降低
①同步方法
public synchronized void method(int args){}
②同步块—Obj同步监视器
锁的对象是变化的量,需要增删改
synchronized(Obj){}
③synchronized方法控制对对象的访问,每个对象对应一把锁,每个synchronized方法必须都获得调用该方法的对象的锁才能执行,否则线程会阻塞,方法一旦执行,就独占该锁,直到该方法返回才释放锁,后面被阻塞的线程才能获得这个锁,继续执行
CopyOnWriteArrayList是JUC安全类型的集合
1 public class TestJUC {
2 //测试JUC安全类型的集合
3 public static void main(String[] args) {
4 CopyOnWriteArrayList<String> list=new CopyOnWriteArrayList<String>();
5 for (int i = 0; i < 10000; i++) {
6 new Thread(()->{
7 list.add(Thread.currentThread().getName());
8 }).start();
9 }
10 ?
11 try {
12 Thread.sleep(3000);
13 } catch (InterruptedException e) {
14 e.printStackTrace();
15 }
16 ?
17 System.out.println(list.size());
18 }
19 }
①死锁就是多个线程各自占有一些共享资源,并且互相等待其他线程占有的资源才能运行,而导致两个或者多个线程都在等待对方释放资源,都停止执行的情形
②产生死锁的必要条件
1.互斥条件:一个资源每次只能被一个进程使用
2.请求与保持条件:一个进程因请求资源而阻塞时,对已获得的资源保持不放
3.不剥夺条件:进程已获得的资源,在未使用完之前,不能强行剥夺
4.循环等待条件:若干进程之间形成一种头尾相接的循环等待资源关系
想办法破坏其中一个或多个条件便可以解开死锁
1 public class TestLock {
2 public static void main(String[] args) {
3 MakeUp g1=new MakeUp(0,"A");
4 MakeUp g2=new MakeUp(1,"B");
5 g1.start();
6 g2.start();
7 }
8 }
9 ?
10 //口红
11 class Lipstick{
12 }
13 ?
14 //镜子
15 class Mirror{
16 }
17 ?
18 class MakeUp extends Thread{
19 //需要的资源只有一份,用static来保证只有一份
20 static Lipstick lipstick=new Lipstick();
21 static Mirror mirror=new Mirror();
22 int choice;//选择
23 String girlname;//使用化妆品的人
24 ?
25 MakeUp(int choice,String girlname){
26 this.choice=choice;
27 this.girlname=girlname;
28 }
29 ?
30 @Override
31 public void run() {
32 //化妆
33 try {
34 makeup();
35 } catch (InterruptedException e) {
36 e.printStackTrace();
37 }
38 }
39 ?
40 private void makeup() throws InterruptedException {
41 if(choice==0){
42 synchronized (lipstick){//获得口红的锁
43 System.out.println(this.girlname+"获得口红的锁");
44 Thread.sleep(1000);
45 synchronized (mirror){//一秒钟后获得镜子的锁
46 System.out.println(this.girlname+"获得了镜子的锁");
47 }
48 }
49 }else{
50 synchronized (mirror){//获得镜子的锁
51 System.out.println(this.girlname+"获得了镜子的锁");
52 Thread.sleep(2000);
53 synchronized (lipstick){//二秒钟后获得口红的锁
54 System.out.println(this.girlname+"获得口红的锁");
55 }
56 }
57 }
58 }
59 }
①从JDK5开始,Java提供了更强大的线程同步机制,通过显式定义同步锁对象来实现同步
②java.util.concurrent.locks.Lock接口是控制多个线程对共享资源进行访问的工具,锁提供了对共享资源的独占访问,每次只能有一个线程对Lock对象加锁,线程开始访问共享资源之前应先获得Lock对象
③ReentrantLock类(可重入锁)实现了Lock
1 class c{
2 private final ReentrantLock lock=new ReentrantLock();
3 public void m(){
4 lock.lock();
5 try{
6 //保证线程安全的代码
7 }finally{
8 lock.unlock();
9 //如果同步代码有异常,要将unlock()写入finally语句块
10 }
11 }
12 }
生产者消费者问题是线程协作。仓库中不存在物品,则消费者要等待生产者生产,否则直接拿走物品;而生产者在仓库中不存在物品时,要生产物品并放入仓库,否则等待消费者取走物品。该问题需要线程同步和线程通信,所以只有synchronized不够。
Java提供了几个方法解决线程之间的通信问题
方法名 | 作用 |
---|---|
wait() | 表示线程一直等待,直到其他线程通知,与sleeep不同,会释放锁 |
wait(long timecut) | 指定等待的毫秒数 |
notify() | 唤醒一个处于等待状态的线程 |
notifyAll() | 唤醒同一个对象上所有调用wait()方法的线程,优先级别高的线程优先调度 |
实现方法
管程法—生产者和消费者共用缓冲区
信号灯法—通过一个标志位实现
提前创建多个线程,并将其放入线程池中;使用时直接获取,使用完放回线程池,可以避免频繁地创建销毁,实现重复利用
好处:提高响应速度、降低资源消耗、便于线程管理
corePoolSize—核心池的大小
maximumPoolSize—最大线程数
keepAliveTime—线程没有任务时最多保持多长时间会终止
线程池接口—ExecutorService
1 public class TestPool {
2 public static void main(String[] args) {
3 //1.创建服务,创建线程池
4 //newFixedThreadPool 参数为:线程池大小
5 ExecutorService service= Executors.newFixedThreadPool(10);
6 //执行
7 service.execute(new MyThread());
8 service.execute(new MyThread());
9 service.execute(new MyThread());
10 //2.关闭连接
11 service.shutdown();
12 }
13 }
14 ?
15 class MyThread implements Runnable{
16 @Override
17 public void run() {
18 System.out.println(Thread.currentThread().getName());
19 }
20 }
原文:https://www.cnblogs.com/yqsumAll/p/14418042.html