Java学习_20220627

多线程详解

1. 线程同步机制

  多个线程访问同一个对象,并且某些线程还想修改这个对象,使用线程同步。是一种等待机制,多个需要同时访问此对象的线程进入这个对象的等待池形成队列,等待前面线程使用完毕,下一个线程再使用。

形成条件:队列+锁 (解决线程安全问题)

(1)锁机制:synchronized,当一个线程获得对象的排它锁,独占资源,其他线程必须等待,使用后释放锁即可。

存在以下问题:

一个线程持有锁会导致其他所有需要此锁的线程挂起,引起性能问题,一个优先级高的线程等待一个优先级低的线程释放锁,会导致优先级倒置,引起性能问题。

两种用法:

synchronized方法和synchronized块

同步方法:public synchronized void method(int args){}

同步方法,默认锁的是this,,,可以锁run方法

同步块:synchronized(obj){}:obj同步监视器,可以是任何对象,使用共享资源(需要修改的对象)作为同步监视器。

锁的对象是变化的量,需要增删改的对象。

@Override
 public void run() { 
    synchronized (account){ //是对account进行操作
        //判断账户中的余额是否足够
        if(account.money-drawingMoney<0){
            System.out.println(Thread.currentThread().getName()+"钱不够了");
            return;
        }
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        //卡内余额
        account.money = account.money-drawingMoney;
        nowMoney = nowMoney+drawingMoney;
        System.out.println(account.name+"余额为:"+account.money);
        System.out.println(this.getName()+"手里的钱"+nowMoney);
      }
    }
}

(2)JUC中关于安全类型的集合List

CopyOnWriteArrayList

CopyOnWriteArrayList<String> list = new CopyOnWriteArrayList<>();
for (int i = 0; i < 1000; i++) {
    new Thread(()->{
        list.add(Thread.currentThread().getName());
    }).start();
}
try {
    Thread.sleep(1000);
} catch (InterruptedException e) {
    e.printStackTrace();
}
System.out.println(list.size());

2.死锁

多个线程互相之间抱着对方需要的资源,形成僵持。

某一个同步块同时拥有“两个以上对象的锁”时,就可能会发生哪个“死锁”的问题。相互等待对方的释放资源,都停止执行

产生死锁的四个必要条件:

(1)互斥条件:一个资源只能被一个进程使用;

(2)请求与保持条件:一个进程因请求资源而阻塞时,对已获得的资源保持不放;

(3)不剥夺条件:进程已获得的资源,在为使用完之前,不能强行剥夺;

(4)循环等待条件:若干进程之间形成一种头尾相接的循环等待资源关系。

3. Lock锁

ReentrantLock 可重入锁,可以显示加锁、释放锁。

定义lock锁,只能锁代码块

class A{
    private final ReentrantLock lock = new ReentrantLock();
    public void m(){
        lock.lock();//加锁
        try{
            //不安全的代码
        }finally{
            lock.unlock();//解锁
            //如果同步代码有异常,要将unlock()写入finally语句块
        }
    }
}

 4. 线程协作

this.wait(),等待,可释放锁

this.notify(),唤醒线程

5. 线程池

提前创建多个线程,放入线程池中,使用时直接获取,使用完放回池中,可以比米娜频繁创建销毁、实现重复利用。提高相应速度,降低资源消耗,便于线程管理。

API:

ExecutorService:线程池接口

void execute(Runnable command):没有返回值,用来执行Runnable

<T> Future <T>submit(Callable<T>task):有返回值,用来执行Callable

void shutdown():关闭连接池

public class TestPool {
    public static void main(String[] args) {
        //创建服务,创建线程池
        //newFixedThreadPool(10),参数为线程池大小
        ExecutorService service = Executors.newFixedThreadPool(10);
        //执行
        service.execute(new MyThread());
        service.execute(new MyThread());
        service.execute(new MyThread());
        service.execute(new MyThread());
        //关闭连接池
        service.shutdown();
    }
}
class MyThread implements Runnable{
    @Override
    public void run() {
        System.out.println(Thread.currentThread().getName());
    }
}

Executors:线程池的工厂类,创建返回不同类型的线程池。

posted @ 2022-06-27 19:31  浑浑噩噩一只小迷七  阅读(27)  评论(0)    收藏  举报