JAVA多线程基础

多线程概念

多线程:多线程就是指一个进程中同时有多个执行路径(线程)正在执行。
进程:应用程序的执行实例,有独立的内存空间和系统资源。
线程:CUP调度和分派的基本单位,执行运算的最小单位,可完成一个独立的顺序控制流程。

一个进程里可以运行多个线程,线程共享了进程的CPU空间,同一个时间点只能运行一个线程,交替。

什么是多线程 如果在一个进程中同时运行了多个线程,用来完成不同的工作则成为多线程 多个线程交替占用CPU资源,而非真正的并行执行

多线程好处
* 充分利用CPU的资源,提升代码性能
* 简化编程模型,更好的软件设计和架构
*带来良好的用户体验

总结:多线程是异步的,但这不代表多线程真的是几个线程是在同时进行,实际上是系统不断地在各个线程之间来回的切换(因为系统切换的速度非常的快,所以给我们在同时运行的错觉)

创建线程的三种方法

第一种方式.继承Thread类,重写run方法即可;(Thread类实现了Runable接口)启动线程用start()
run方法没有返回值

public class xian1 extends Thread{
    public void run(){
        for (int i = 0; i < 5; i++) {
            System.out.println("线程"+i);
        }
    }
}
class Test1{
    public static void main(String[] args) {//main线程为主线程
        xian1 x1=new xian1();
        x1.start();
        for (int i = 0; i < 5; i++) {
            System.out.println("主线程"+i);
        }
    }
}

当然也可通过匿名内部类的方式创建线程 如下:

    public static void main(String[] args) {
        xian1 x1=new xian1();
        x1.start();
        for (int i = 0; i < 5; i++) {
            System.out.println("主线程"+i);
        }
        new Thread(new Runnable() {
            @Override
            public void run() {
                for (int i = 0; i < 4; i++) {
                    System.out.println("匿名内部类"+i);
                }
            }
        }).start();
    }

小结

thread.getname()获取名称 thread.setname()重新设置名称

–(把你想通过线程执行的主体写在run方法里)

是否可以调用run()启动线程?–不可以
(1)只有主线程一个执行路径
(2)依次调用了两次run()方法
run()方法被当做main()中的一个普通方法执行,失去了线程的意义
第二种方式:实现类Runnable接口 然后实现run方法

public class xian4 implements Runnable{
    @Override
    public void run() {
        for (int i = 0; i < 6; i++) {
            System.out.println("子线程"+i+"线程名"+Thread.currentThread().getName());
        }
    }
}
class Test6{
    public static void main(String[] args) {
        xian4 x4=new xian4();
        Thread thread=new Thread(x4);
        thread.start();
        for (int i = 0; i < 6; i++) {
            System.out.println("主线程"+i);
        }
    }
}

匿名内部类

 Runnable runnable=new Runnable() {
            @Override
            public void run() {
                for (int i = 0; i < 4; i++) {
                    System.out.println("匿名内部类"+i);
                }
            }
        };
        Thread thread1=new Thread(runnable);
        thread1.start();

第三种方式:实现Callable接口(匿名内部类也一起写在下面)

import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.FutureTask;

//继承Thread类 与实现runnable接口 统统不能有返回值(拿不到返回的结果) 也无法抛出异常
public class MyCallable implements Callable {
    @Override
    public Object call() throws Exception {
        System.out.println(Thread.currentThread().getName()+"开始计算");
        int sum = 0;
        for (int i = 0; i <= 100; i++) {
            sum+=i;
        }
        return sum;
    }
}
class TestCallable{
    public static void main(String[] args) throws ExecutionException, InterruptedException {
        //1创建callable对象
        Callable<Integer> callable = new MyCallable();
        //2 将callable对象 转换成可执行的任务对象(FutureTask) 因为需要通过任务对象拿回返回结果
        FutureTask<Integer> futureTask = new FutureTask<>(callable);
        //3创建一个线程
        Thread thread = new Thread(futureTask);
        //4启动线程
        thread.start();
        Integer o = futureTask.get();
        System.out.println(o);


        System.out.println("==================");
        Callable<Integer> callable1  =new Callable<Integer>() {
            @Override
            
                System.out.println(Thread.currentThread().getName()+"开始计算");
                int sum = 0;
                for (int i = 0; i <= 100; i++) {
                    sum+=i;
                }
                return sum;
            }
        };
        FutureTask<Integer> integerFutureTask = new FutureTask<>(callable1);
        new Thread(integerFutureTask).start();
        Integer integer = integerFutureTask.get();
        System.out.println(integer);

        /*
         FutureTask<Integer> integerFutureTask = new FutureTask<>(new Callable<Integer>() {
            @Override
            public Integer call() throws Exception {
                System.out.println(Thread.currentThread().getName()+"开始计算");
                int sum = 0;
                for (int i = 0; i <= 100; i++) {
                    sum+=i;
                }
                return sum;
            }
        });
        new Thread(integerFutureTask).start();
        Integer integer = integerFutureTask.get();
        System.out.println(integer);
         */
    }
}

常用方法和线程调度

线程调度:线程调度指按照特定机制为多个线程分配CPU的使用权
优先级和休眠
设置线程优先级
setPriority(Thread.MAX_PRIORITY);优先级最大为10最小为1
setPriority(Thread.MIN_PRIORITY);不是百分百按优先级
getPriority()获取优先级
getPriority()
重要
Thread.sleep(1000);参数为毫秒数 表示休眠的时间
Thread.yield(): 线程礼让
释放当前线程执行的权利 但是不会释放锁 只让有相同执行权的其他线程获取cpu片段 但是 不是交出cpu片段
只是让我这个线程恢复到一个就绪状态 但是不是让这个线程停止
不是百分百成功
join():调用join方法
线程a中调用线程b.join()方法 此时a线程 进入阻塞状态
直到b执行完 a才会结束阻塞状态

守护线程:主线程结束 守护线程随之而去
主线程执行完毕,不管子线程执行到哪里都会结束

DeamonThread d1 = new DeamonThread();
d1.setDaemon(true);
d1.start();

public class ShouHu extends Thread{
    public void run(){
        for (int i = 0; i < 1000; i++) {
            System.out.println(Thread.currentThread().getName()+i);
            try {
                Thread.sleep(500);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}
class Test{
    public static void main(String[] args) {
        ShouHu shouHu=new ShouHu();
        shouHu.setDaemon(true);
       // shouHu.setDaemon(false);
        shouHu.start();
        for (int i = 0; i < 10; i++) {
            System.out.println(Thread.currentThread().getName()+i);
            try {
                Thread.sleep(500);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}

多线程共享数据问题
多个线程操作同一共享资源时,将引发数据不安全问题
原因:多线程共同操作数据时,引发的冲突(如延迟时,操作未全部完成等等)
解决方案:
同步方法
synchronized就是为当前的线程声明一把锁
访问修饰符 synchronized 返回类型 方法名(参数列表){。。。。}
synchronized访问修饰符 返回类型 方法名(参数列表){。。。}
同步代码块
synchronized(this){//需要同步的代码块}

public class SuoFangFa implements Runnable{
    private  static int ticket=100;
    @Override
    public void run() {
        while (true){
            if (!sale1()){
                break;
            }
        }
    }
    public static boolean sale() {
        synchronized (SuoFangFa.class) {
            if (ticket <= 0) {
                return false;
            }
            System.out.println(Thread.currentThread().getName() + "卖了" + ticket + "票");
            ticket--;
            return true;
        }
    }
    public synchronized boolean sale1(){
        if(ticket<=0){
            return false;
        }
        System.out.println(Thread.currentThread().getName()+"卖了"+ticket+"票");
        ticket--;
        return true;
    }
    //如果是静态资源要锁类(因为静态资源被多个实例共享)
    public static synchronized boolean sale2(){ //相当于锁 类.class
        if(ticket<=0){
            return false;
        }
        System.out.println(Thread.currentThread().getName()+"卖了"+ticket+"票");
        ticket--;
        return true;

    }
}
class Test88{
    public static void main(String[] args) {
        SuoFangFa t=new SuoFangFa();
        //线程对象
        Thread win1 = new Thread(t,"窗口1");
        Thread win2 = new Thread(t,"窗口2");
        Thread win3 = new Thread(t,"窗口3");
        Thread win4 = new Thread(t,"窗口4");

        win1.start();
        win2.start();
        win3.start();
        win4.start();
    }
}

输出结果

加完锁后会按照顺序执行,不会出现错乱,乱序不安全现象

窗口1卖了100票
窗口1卖了99票
窗口1卖了98票
窗口1卖了97票
窗口1卖了96票
窗口4卖了95票
窗口4卖了94票
窗口4卖了93票
窗口4卖了92票
窗口4卖了91票
窗口4卖了90票
窗口4卖了89票
窗口4卖了88票
窗口4卖了87票
窗口4卖了86票
窗口4卖了85票
窗口4卖了84票
。。。

死锁问题

举个例子:两个男孩各有一支筷子,都想得到另一只筷子吃饭,两个人同时抓到另一只筷子都不松手,在这一直僵持不动,都想等对方松手,结果就是两人都不能吃饭,这就是死锁。

所谓死锁是指多个线程竞争资源而造成的一种僵局(互相等待)若无外力作用,这些进程都将无法向前推进
*

this.wait();进入等待队列同时释放自己的cpu锁
this.notify();唤醒线程
this.notifyAll();唤醒全部线程

创建一个银行取钱存钱的例子(复现死锁问题)
创建一个银行类

public class BankCard {
    private double money;//余额

    public double getMoney() {
        return money;
    }

    public void setMoney(double money) {
        this.money = money;
    }
    private boolean flag=false;//true 表示有钱可以取  false 表示没钱可以存 不能取
    public synchronized void save(double m){
        while (flag){//没钱
            try {
                this.wait();//进入等待队列 同时 释放了自己的cup 锁
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        money=money+m;
        System.out.println(Thread.currentThread().getName()+"存了"+m+"余额是"+money);
        //改标记true
        flag=true;
        this.notify();//唤醒

    }
    public synchronized void take(double m){
        while (!flag){
            try {
                this.wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        money=money-m;
        System.out.println(Thread.currentThread().getName()+"取了"+m+",余额是"+money);
        //取走了 改标记为 false
        flag = false;
        this.notify();
    }
}

创建存钱线程

public class AddMoney implements Runnable{
    private BankCard card;

    public AddMoney(BankCard card) {
        this.card = card;
    }

    @Override
    public void run() {
        for (int i = 0; i < 10; i++) {
            card.save(1000);
        }
    }
}

创建取钱线程

public class SubMoney implements Runnable{
    private  BankCard card;

    public SubMoney(BankCard card) {
        this.card = card;
    }

    @Override
    public void run() {
        for (int i = 0; i < 10; i++) {
            card.take(1000);
        }
    }
}

测试类

public class Test11 {
    public static void main(String[] args) {
        BankCard card=new BankCard();
        AddMoney add=new AddMoney(card);
        SubMoney sub=new SubMoney(card);
        Thread thread=new Thread(add,"男孩1");
        Thread thread1=new Thread(sub,"女孩1");
        Thread thread3=new Thread(add,"男孩2");
        Thread thread4=new Thread(sub,"女孩2");
        thread.start();
        thread1.start();
        thread3.start();
        thread4.start();

    }
}

输出结果(死锁)

男孩1存了1000.0余额是1000.0
女孩1取了1000.0,余额是0.0
男孩2存了1000.0余额是1000.0
女孩1取了1000.0,余额是0.0
男孩1存了1000.0余额是1000.0
程序一直僵持不会结束

下面来看正确的程序
创建银行类(注意唤醒方法notifyAll是唤醒全部)

public class BankCard {
    private double money;

    public double getMoney() {
        return money;
    }

    public void setMoney(double money) {
        this.money = money;
    }
    private boolean flag=false;
    public synchronized void save(double m){
        while (flag){
            try {
                this.wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        money=money+m;
        System.out.println(Thread.currentThread().getName()+"存了"+m+"余额是"+money);
        flag=true;
        this.notifyAll();
    }
    public synchronized void take(double m){
        while (!flag){
            try {
                this.wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        money=money-m;
        System.out.println(Thread.currentThread().getName()+"取了"+m+",余额是"+money);
        flag=false;
        this.notifyAll();
    }
}

存钱线程

public class AddMoney implements Runnable{
    private BankCard card;

    public AddMoney(BankCard card) {
        this.card = card;
    }

    @Override
    public void run() {
        for (int i = 0; i < 10; i++) {
            card.save(1000);
        }
    }
}

取钱线程

public class SubMoney implements Runnable{
    private BankCard card;

    public SubMoney(BankCard card) {
        this.card = card;
    }

    @Override
    public void run() {
        for (int i = 0; i < 10; i++) {
            card.take(1000);
        }
    }
}

测试类

public class Test4 {
    public static void main(String[] args) {
        BankCard card=new BankCard();
        AddMoney add=new AddMoney(card);
        SubMoney sub=new SubMoney(card);
        Thread t1=new Thread(add,"男孩1");
        Thread t2=new Thread(sub,"女孩1");
        Thread t3=new Thread(add,"男孩2");
        Thread t4=new Thread(sub,"女孩2");
        t1.start();
        t2.start();
        t3.start();
        t4.start();
    }
}

输出结果

男孩1存了1000.0余额是1000.0
女孩2取了1000.0,余额是0.0
男孩2存了1000.0余额是1000.0
女孩1取了1000.0,余额是0.0
男孩2存了1000.0余额是1000.0
女孩2取了1000.0,余额是0.0
男孩1存了1000.0余额是1000.0
女孩2取了1000.0,余额是0.0
男孩2存了1000.0余额是1000.0
女孩1取了1000.0,余额是0.0
男孩2存了1000.0余额是1000.0
女孩2取了1000.0,余额是0.0
男孩1存了1000.0余额是1000.0
女孩2取了1000.0,余额是0.0
男孩2存了1000.0余额是1000.0
女孩1取了1000.0,余额是0.0
男孩2存了1000.0余额是1000.0
女孩2取了1000.0,余额是0.0
男孩1存了1000.0余额是1000.0
女孩2取了1000.0,余额是0.0
男孩2存了1000.0余额是1000.0
女孩1取了1000.0,余额是0.0
男孩2存了1000.0余额是1000.0
女孩2取了1000.0,余额是0.0
男孩1存了1000.0余额是1000.0
女孩2取了1000.0,余额是0.0
男孩2存了1000.0余额是1000.0
女孩1取了1000.0,余额是0.0
男孩2存了1000.0余额是1000.0
女孩2取了1000.0,余额是0.0
男孩1存了1000.0余额是1000.0
女孩1取了1000.0,余额是0.0
男孩1存了1000.0余额是1000.0
女孩1取了1000.0,余额是0.0
男孩1存了1000.0余额是1000.0
女孩1取了1000.0,余额是0.0
男孩1存了1000.0余额是1000.0
女孩1取了1000.0,余额是0.0
男孩1存了1000.0余额是1000.0
女孩1取了1000.0,余额是0.0
正确结果
Process finished with exit code 0

线程池

什么是线程池:线程池就是创建若干个可执行的线程放入一个池(容器)中,有任务需要处理时,会提交到线程池中的任务队列,处理完之后线程并不会被销毁,而是仍然在线程池中等待下一个任务。

线程状态-----根据下图理解我所说的
1.初始(NEW) : 新创建了一个线程对像,但还没有调用Start()方法
2、运行(RUNNABLE) : Java线程中将就绪(ready)和运行中(running)两种状态笼统的称为“运行”。
线程对象创建后;其他线程(比如main线程)调用该对象的Start(方法。该状态的线程位于可运行线程池中,等待被线程调度选中获取CPU的使用权,此时处于就绪状态(ready)就绪状态的线程在获得CPU时间片后变为运行中状态(running)
3.阻塞(BLOckED) : 表示线程阻塞于锁
4.笔待(WAITNG) : 进入该状态的线程需要等待其他线程做出一些特定动作(通知或中断)
5.超等待(TIMED_WAITING) : 该状态不同于WAITING,它可以在指定的时间后自行返回
6.终止(TERMINATED) : 表示该线程已经执行完毕
线程一旦终止不能复生,在一个终止的线程上调用start()方法会抛出Java.lang.leqal Thread stuteExiption异常
在这里插入图片描述
四种创建线程池的方式

public class QiCanShu {
    public static void main(String[] args) {
       // Executor executor=new ThreadPoolExecutor(这里有七个参数 );
       //利用Executors工具类默认提供的四种创建线程池的方式
        //1 创建固定个数的线程池
        ExecutorService executorService1= Executors.newFixedThreadPool(4);
        //2 创建一个缓存线程池 线程个数有任务个数决定
        ExecutorService executorService2=Executors.newCachedThreadPool();
        //3 创建单一线程池的线程池
        ExecutorService executorService3=Executors.newSingleThreadExecutor();
        //4 创建可调度的线程池(做一些定时任务) 可用时间控制他
        ScheduledExecutorService scheduledExecutorService = Executors.newScheduledThreadPool(3);

    }
}

大概步骤:
创建线程池
创建一个任务
提交任务
关闭任务
创建一个缓存线程池


public class Demo02 {
    public static void main(String[] args) {
        //1创建线程池
        ExecutorService es = Executors.newCachedThreadPool();


        //创建一个任务出来
        Runnable runnable = new Runnable() {
            private int ticket =100;//票
            @Override
            public void run() {
                //售卖
                while (true){
                    if(ticket<=0){
                        break;
                    }
                    System.out.println(Thread.currentThread().getName()+"卖了"+ticket+"张票");
                    ticket--;
                }
            }
        };

        //提交任务
        for (int i = 0; i < 5; i++) {
            es.submit(runnable); //可以放callable 并且获取返回值
//            es.execute(runnable); //只能放Runnable 仅仅只是执行线程
        }

        //线程池 需要关闭
        es.shutdown(); //当我线程任务结束之后 线程池关闭
//        es.shutdownNow(); // 直接关 不论是否有正在执行的线程
    }
}

输出结果

pool-1-thread-3卖了100票
pool-1-thread-2卖了100票
pool-1-thread-1卖了100票
pool-1-thread-4卖了100票
pool-1-thread-1卖了97票
pool-1-thread-5卖了98票
pool-1-thread-2卖了98票
pool-1-thread-3卖了99票
pool-1-thread-2卖了93票
pool-1-thread-5卖了94票
pool-1-thread-1卖了95票
pool-1-thread-1卖了89票
pool-1-thread-1卖了88票
pool-1-thread-1卖了87票
pool-1-thread-1卖了86票
pool-1-thread-4卖了96票
pool-1-thread-1卖了85

创建固定线程池

public class GuDing {
    public static void main(String[] args) {
        //创建线程池
        ExecutorService executorService = Executors.newFixedThreadPool(3);
        //创建任务
        Runnable runnable=new Runnable() {
            private int ticket=100;
            @Override
            public void run() {
                while (true) {
                    if (ticket <= 0) {
                        break;
                    }
                    System.out.println(Thread.currentThread().getName() + "卖了" + ticket + "张票");
                    ticket--;
                }
            }
        };
        //提交任务
        for (int i = 0; i < 5; i++) {
            executorService.submit(runnable);
        }
        //关闭线程池
        executorService.shutdown();
    }
}

pool-1-thread-1卖了69张票
pool-1-thread-3卖了66张票
pool-1-thread-2卖了67张票
pool-1-thread-3卖了64张票
pool-1-thread-1卖了65张票
pool-1-thread-3卖了62张票
pool-1-thread-2卖了63张票
pool-1-thread-3卖了60张票
pool-1-thread-1卖了61张票
pool-1-thread-3卖了58张票
pool-1-thread-2卖了59张票
可以看到最多有3个线程在执行,因为我们设置了线程个数

创建定时器

public class DingShi {
    public static void main(String[] args) {
        ScheduledExecutorService ses = Executors.newScheduledThreadPool(5);
        //延迟执行
        /*ses.schedule(new Runnable() {
            @Override
            public void run() {
                System.out.println(new Date()+"延迟运行");
            }
        },3, TimeUnit.SECONDS);*/
       // ses.shutdown();
        //定时器
        ses.scheduleAtFixedRate(new Runnable() {
            @Override
            public void run() {
                System.out.println(Thread.currentThread().getName()+new Date()+"延迟运行");
            }
        },3,3,TimeUnit.SECONDS);



    }
}

输出结果

pool-1-thread-1Sun Nov 06 18:11:49 CST 2022延迟运行
pool-1-thread-1Sun Nov 06 18:11:52 CST 2022延迟运行
pool-1-thread-2Sun Nov 06 18:11:55 CST 2022延迟运行
pool-1-thread-1Sun Nov 06 18:11:58 CST 2022延迟运行
pool-1-thread-3Sun Nov 06 18:12:01 CST 2022延迟运行
pool-1-thread-3Sun Nov 06 18:12:04 CST 2022延迟运行
pool-1-thread-3Sun Nov 06 18:12:07 CST 2022延迟运行
pool-1-thread-3Sun Nov 06 18:12:10 CST 2022延迟运行
pool-1-thread-3Sun Nov 06 18:12:13 CST 2022延迟运行
pool-1-thread-3Sun Nov 06 18:12:16 CST 2022延迟运行

创建单一线程池

 public static void main(String[] args) {
        //创建线程池
      //  ExecutorService executorService = Executors.newFixedThreadPool(3);
        //创建单一线程池
        ExecutorService executorService1 = Executors.newSingleThreadExecutor();
        //创建任务
        Runnable runnable=new Runnable() {
            private int ticket=100;
            @Override
            public void run() {
                while (true) {
                    if (ticket <= 0) {
                        break;
                    }
                    System.out.println(Thread.currentThread().getName() + "卖了" + ticket + "张票");
                    ticket--;
                }
            }
        };
        //提交任务
        for (int i = 0; i < 5; i++) {
            executorService1.submit(runnable);
        }
        //关闭线程池
        executorService1.shutdown();
    }

输出结果

pool-1-thread-1卖了100张票
pool-1-thread-1卖了99张票
pool-1-thread-1卖了98张票
pool-1-thread-1卖了97张票
pool-1-thread-1卖了96张票
pool-1-thread-1卖了95张票
pool-1-thread-1卖了94张票
pool-1-thread-1卖了93张票
pool-1-thread-1卖了92张票
pool-1-thread-1卖了91张票
pool-1-thread-1卖了90张票
pool-1-thread-1卖了89张票
pool-1-thread-1卖了88张票
pool-1-thread-1卖了87张票
pool-1-thread-1卖了86张票
pool-1-thread-1卖了85张票
pool-1-thread-1卖了84张票
pool-1-thread-1卖了83张票
pool-1-thread-1卖了82张票
pool-1-thread-1卖了81张票
pool-1-thread-1卖了80张票
pool-1-thread-1卖了79张票
pool-1-thread-1卖了78张票
pool-1-thread-1卖了77张票
可以看出只有一个线程在运行

可以通过Callable获取返回值

public class BingFa {
    //并发计算 1~50  51 ~100 拿到结果 在进行拼接
    public static void main(String[] args) throws ExecutionException, InterruptedException {
        ExecutorService es = Executors.newFixedThreadPool(2);
        Future<Integer> sub1 = es.submit(new Callable<Integer>() {

            @Override
            public Integer call() throws Exception {
                int sum=0;
                for (int i = 1; i <= 50; i++) {
                    sum+=i;
                    Thread.sleep(10);
                }
                System.out.println("1-50计算完毕");
                return sum;
            }
        });
            Future<Integer> sub2 = es.submit(new Callable<Integer>() {
                @Override
                public Integer call() throws Exception {
                    int sum1=0;
                    for (int i = 51; i <=100 ; i++) {
                        sum1+=i;
                        Thread.sleep(10);
                    }
                    System.out.println("51-100计算完毕");
                    return sum1;
                }
            });
        System.out.println(sub1.get()+sub2.get());
        es.shutdown();
    }
}

输出结果

1-50计算完毕
51-100计算完毕
5050

ReentrantLock()

ReentrantLock()重入锁:可重新反复进入的锁,但仅限于当前线程
lock.lock();加锁
lock.unlock();释放锁


ReentrantLock()重入锁运用

public class LockSuo {
    //Re-Entrant-Lock:即表示可重新反复进入的锁,但仅限于当前线程;
    private String[]str={"A","B","","",""};
    private int count=2;
    private Lock lock=new ReentrantLock();
    public void add(String v){
        //加锁
        try {
            lock.lock();
            str[count]=v;
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            count++;
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            lock.unlock();//释放锁
        }
        System.out.println(Thread.currentThread().getName()+"成功添加"+v);
    }
    public void print(){
        System.out.println(Arrays.toString(str));
    }
}
class Testt{
    public static void main(String[] args) throws InterruptedException {
        LockSuo lockSuo=new LockSuo();
        Runnable runnable=new Runnable() {
            @Override
            public void run() {
                lockSuo.add("aaa");
            }
        };
        Runnable runnable1=new Runnable() {
            @Override
            public void run() {
                lockSuo.add("bbb");
            }
        };
        Thread t1=new Thread(runnable);
        Thread t2=new Thread(runnable1);

        t1.start();
        t2.start();
        t1.join();
        t2.join();
        lockSuo.print();
    }
}

输出结果

Thread-0成功添加aaa
Thread-1成功添加bbb
[A, B, aaa, bbb, ]

读写锁操作

ReentrantLock()是独占锁某一时刻只有一个线程可以获得该锁
ReentrantReadWriteLock采用读写分离的策略允许多个线程可以同时获取读锁 读锁可以被多个线程同时获取
写锁只能被一个线程获取 读写锁之间是互斥的

直接上代码

public class DuXieSuo {
    //
    private Lock lock=new ReentrantLock();
    private String value;

    private ReentrantReadWriteLock rrl=new ReentrantReadWriteLock();//创建
    //换成读写锁来操作
    private ReentrantReadWriteLock.ReadLock readLock=rrl.readLock();
    private ReentrantReadWriteLock.WriteLock writeLock= rrl.writeLock();
    //读

    public String getValue() {
        readLock.lock();//读锁
        try {
            try {
                Thread.sleep(3000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("读取了"+value);
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            readLock.unlock();//释放读锁
        }
        return value;
    }

    //写
    public void setValue(String value) {
        writeLock.lock();//写锁
        try {
            try {
                Thread.sleep(3000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("写入"+value);
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            writeLock.unlock();//释放写锁
        }
        this.value = value;
    }
}
class Test6{
    public static void main(String[] args) {
        DuXieSuo duXieSuo=new DuXieSuo();
        ExecutorService executorService = Executors.newFixedThreadPool(20);

        Runnable read=new Runnable() {
            @Override
            public void run() {
                duXieSuo.getValue();
            }
        };

        Runnable write=new Runnable() {
            @Override
            public void run() {
                duXieSuo.setValue("aaaaaaa");
            }
        };
        long l1=System.currentTimeMillis();//计算程序刚开始执行时间
        for (int i = 0; i < 4; i++) {
            executorService.submit(write);//提交任务
        }
        for (int i = 0; i < 16; i++) {
            executorService.submit(read);
        }
        executorService.shutdown();//结束任务
        while (!executorService.isTerminated()){
            //空转
        }//是否还有存活线程 在计算执行时间时顺利进行
        long l2=System.currentTimeMillis();//程序结束时间
        System.out.println(l2-l1);//最后运行时间
    }
}

输出结果

写入aaaaaaa
写入aaaaaaa
写入aaaaaaa
写入aaaaaaa
读取了aaaaaaa
读取了aaaaaaa
读取了aaaaaaa
读取了aaaaaaa
读取了aaaaaaa
读取了aaaaaaa
读取了aaaaaaa
读取了aaaaaaa
读取了aaaaaaa
读取了aaaaaaa
读取了aaaaaaa
读取了aaaaaaa
读取了aaaaaaa
读取了aaaaaaa
读取了aaaaaaa
读取了aaaaaaa
15060//毫秒


Process finished with exit code 0

Condition
比较重要面试会问到
条件唤醒 可以控制线程的顺序

public class HuanXing {
    public static void main(String[] args) {
        Lock lock=new ReentrantLock();
        Condition c1=lock.newCondition();
        // await() 阻塞当前线程 当调用c1.await()
        // singal() 唤醒线程  当调用c1.singal() 线程激活
        Condition c2 = lock.newCondition();
        Condition c3 = lock.newCondition();

        new Thread(new Runnable() {
            @Override
            public void run() {
                lock.lock();
                try {
                    c1.await();
                    try {
                        Thread.sleep(1000);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    System.out.println("粒粒皆辛苦");
                } catch (InterruptedException e) {
                    e.printStackTrace();
                } finally {
                    lock.unlock();
                }
            }
        }).start();

        new Thread(new Runnable() {
            @Override
            public void run() {
                lock.lock();
                try {
                    c2.await();
                    try {
                        Thread.sleep(1000);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    System.out.println("谁知盘中餐");
                    c1.signal();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                } finally {
                    lock.unlock();
                }
            }
        }).start();
        new Thread(new Runnable() {
            @Override
            public void run() {
                lock.lock();
                try {
                    c3.await();
                    try {
                        Thread.sleep(1000);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    System.out.println("汗滴禾下土");
                    c2.signal();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                } finally {
                    lock.unlock();
                }
            }
        }).start();
        new Thread(new Runnable() {
            @Override
            public void run() {
                lock.lock();
                try {
                    try {
                        Thread.sleep(1000);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    System.out.println("锄禾日当午");
                    c3.signal();
                } catch (Exception e) {
                    e.printStackTrace();
                } finally {
                    lock.unlock();
                }
            }
        }).start();
    }
}

输出结果

锄禾日当午
汗滴禾下土
谁知盘中餐
粒粒皆辛苦

Process finished with exit code 0
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值