33-Java多线程

33-Java多线程-qianfeng-笔记



一、什么是多线程

①:什么是进程

在这里插入图片描述

②:什么是线程

在这里插入图片描述

③:进程与线程的区别

在这里插入图片描述

二、线程的组成

①:组成

在这里插入图片描述

②:线程的特点

在这里插入图片描述

③:创建线程的三种方式

在这里插入图片描述

01.【继承Thread类,重写run方法】

1. 代码实现
package com.example.d6_thread;

public class MyThread extends Thread{
    @Override
    public void run() {
        for (int i = 0; i < 100; i++) {
            System.out.println("子线程..........." + i);
        }
    }
}
package com.example.d6_thread;

public class TestThread {
    public static void main(String[] args) {
        // 1.创建线程对象
        MyThread myThread = new MyThread();
        // 2.启动线程
        myThread.start();
        // 3.主线程执行
        for (int i = 0; i < 100; i++) {
            System.out.println("主线程=======================" + i);
        }
    }
}

在这里插入图片描述

2.获取线程名称和Id

在这里插入图片描述

方式一:
在这里插入图片描述在这里插入图片描述
方式二:
在这里插入图片描述在这里插入图片描述

3.修改线程的名称

方式一:
在这里插入图片描述在这里插入图片描述
方式二:
在这里插入图片描述在这里插入图片描述在这里插入图片描述

4. 窗口买票案例

在这里插入图片描述

package com.example.d6_thread;

public class TicketWin extends Thread{
    private int ticketCount = 100;
    public TicketWin() {
    }

    public TicketWin(String name) {
        super(name);
    }

    @Override
    public void run() {
        while (ticketCount > 0){
            System.out.println(Thread.currentThread().getName()+" 卖出了第 " + (101-ticketCount) + "张票~~~~");
            ticketCount--;
        }
    }
}
package com.example.d6_thread;

public class TestTicket {
    public static void main(String[] args) {
        TicketWin ticketWin = new TicketWin("窗口1");
        TicketWin ticketWin2 = new TicketWin("窗口2");
        TicketWin ticketWin3 = new TicketWin("窗口3");
        TicketWin ticketWin4 = new TicketWin("窗口4");
        ticketWin.start();
        ticketWin2.start();
        ticketWin3.start();
        ticketWin4.start();
    }
}

在这里插入图片描述

02.【实现Runnable接口】

1.代码实现

方式一:

package com.example.d6_thread;

public class MyRunnable implements Runnable{
    @Override
    public void run() {
        for (int i = 0; i < 100; i++) {
            System.out.println("线程名称:" + Thread.currentThread().getName() + i);
        }
    }
}
package com.example.d6_thread;

public class TestRunnable {
    public static void main(String[] args){
        MyRunnable myRunnable = new MyRunnable();
        Thread thread = new Thread(myRunnable,"我的线程");
        thread.start();
        for (int i = 0; i < 100; i++) {
            System.out.println("main...................." + i);
        }
    }
}

在这里插入图片描述

方式二:使用匿名内部类实现

package com.example.d6_thread;

public class TestRunnable {
    public static void main(String[] args){
        Runnable runnable = new Runnable() {
            @Override
            public void run() {
                for (int i = 0; i < 100; i++) {
                    System.out.println("线程名称:" + Thread.currentThread().getName() + i);
                }
            }
        };
        // 创建线程对象
        Thread thread = new Thread(runnable,"我的线程1  ");
        thread.start();
        for (int i = 0; i < 100; i++) {
            System.out.println("main...................." + i);
        }
    }
}

在这里插入图片描述

2.Runnable案例1

在这里插入图片描述

package com.example.d7_runnableDemo;

public class Ticket implements Runnable{
    private static int ticketNum = 100;
    @Override
    public void run() {
        while (ticketNum > 0){
            System.out.println("线程名称:" + Thread.currentThread().getName() + (101 - ticketNum));
            ticketNum --;
        }
    }
}
package com.example.d7_runnableDemo;

public class TestTicket {
    public static void main(String[] args) {
        Ticket ticket = new Ticket();
        Thread thread = new Thread(ticket,"窗口1 ");
        Thread thread2 = new Thread(ticket,"窗口2 ");
        Thread thread3 = new Thread(ticket,"窗口3 ");
        Thread thread4 = new Thread(ticket,"窗口4 ");
        thread.start();
        thread2.start();
        thread3.start();
        thread4.start();
    }
}

票数卖重的情况后面会解决
在这里插入图片描述

3.Runnable案例2

在这里插入图片描述> 方式一:

package com.example.d7_runnableDemo;

public class BankCard {
    private int money;

    public int getMoney() {
        return money;
    }

    public void setMoney(int money) {
        this.money = money;
    }
}
package com.example.d7_runnableDemo;

public class AddMoney implements Runnable{
    private BankCard bankCard;

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

    @Override
    public void run() {
        for (int i = 0; i < 10; i++) {
            bankCard.setMoney(bankCard.getMoney() + 1000);
            System.out.println(Thread.currentThread().getName() + "存了1000元"+ " 余额为:" +bankCard.getMoney()+"元~");
        }
    }
}
package com.example.d7_runnableDemo;

public class SubMoney implements Runnable{
    private BankCard bankCard;

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

    @Override
    public void run() {
        for (int i = 0; i < 10; i++) {
            if (bankCard.getMoney() >= 1000){
                bankCard.setMoney(bankCard.getMoney() - 1000);
                System.out.println(Thread.currentThread().getName() + "取了1000元"+ " 余额为:" +bankCard.getMoney()+"元!");
            }else {
                System.out.println("余额不足,赶快存钱。。。。。");
                i--;
            }
        }
    }
}
package com.example.d7_runnableDemo;

public class TestBankCard {
    public static void main(String[] args) {
        BankCard bankCard = new BankCard();
        AddMoney addMoney = new AddMoney(bankCard);
        SubMoney subMoney = new SubMoney(bankCard);
        Thread thread = new Thread(addMoney,"小黑 ");
        Thread thread1 = new Thread(subMoney, "小美 ");
        thread.start();
        thread1.start();
    }
}

方式二:匿名内部类实现方式

package com.example.d7_runnableDemo;

public class TestBankCard2 {
    public static void main(String[] args) {
        BankCard bankCard = new BankCard();

        Runnable add = new Runnable() {
            @Override
            public void run() {
                for (int i = 0; i < 10; i++) {
                    bankCard.setMoney(bankCard.getMoney() + 1000);
                    System.out.println(Thread.currentThread().getName() + "存了1000元"+ " 余额为:" +bankCard.getMoney()+"元~");
                }
            }
        };

        Runnable sub = new Runnable() {
            @Override
            public void run() {
                for (int i = 0; i < 10; i++) {
                    if (bankCard.getMoney() >= 1000){
                        bankCard.setMoney(bankCard.getMoney() - 1000);
                        System.out.println(Thread.currentThread().getName() + "取了1000元"+ " 余额为:" +bankCard.getMoney()+"元!");
                    }else {
                        System.out.println("余额不足,赶快存钱。。。。。");
                        i--;
                    }
                }
            }
        };

        new Thread(add,"小白 ").start();
        new Thread(sub,"小美 ").start();
    }
}

在这里插入图片描述

03.实现Callable接口

计算1-100的和

1.用法一
在这里插入代码片package com.example.d10_executor;

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

public class CallableThread {
    public static void main(String[] args) throws ExecutionException, InterruptedException {
        // 创建一个Callable对象 完成1-100的和
        Callable<Integer> callable = 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;
            }
        };
        // 将Callable 转换成可执行对象
        FutureTask<Integer> futureTask = new FutureTask<>(callable);
        // 创建线程并启动
        new Thread(futureTask).start();
        // 获取结果(等待Callable执行完毕)
        Integer integer = futureTask.get();

        System.out.println("结果是:" + integer);



    }
}

在这里插入图片描述

2.用法二 (结合线程池使用)
package com.example.d10_executor;

import java.util.concurrent.*;

public class CallableThread2 {

    public static void main(String[] args) throws ExecutionException, InterruptedException {
        // 1.创建线程池
        ExecutorService pool = Executors.newFixedThreadPool(1);
        // 2.提交任务
        Future<Integer> future = pool.submit(new Callable<Integer>() {
            @Override
            public Integer call() throws Exception {
                int sum = 0;
                System.out.println(Thread.currentThread().getName() + "开始计算~");
                for (int i = 0; i < 100; i++) {
                    sum += i;
                }
                return sum;
            }
        });
        // 3.获取结果
        Integer integer = future.get();
        System.out.println("结果是:" + integer);
        // 4.关闭线程池
        pool.shutdown();
    }
}

在这里插入图片描述

3.并发计算
package com.example.d10_executor;

import java.util.concurrent.*;

public class CallableThread3 {
    public static void main(String[] args) throws ExecutionException, InterruptedException {
        // 1.创建一个线程池
        ExecutorService pool = Executors.newFixedThreadPool(2);
        // 2.1 创建任务1
        Future<Integer> future1 = pool.submit(new Callable<Integer>() {
            @Override
            public Integer call() throws Exception {
                int sum1 = 0;
                System.out.println(Thread.currentThread().getName() + "计算开始~");
                for (int i = 0; i < 50; i++) {
                    sum1 += i;
                }
                return sum1;
            }
        });
        // 2.2 创建任务2
        Future<Integer> future2 = pool.submit(new Callable<Integer>() {
            @Override
            public Integer call() throws Exception {
                int sum2 = 0;
                System.out.println(Thread.currentThread().getName() + "计算开始~");
                for (int i = 50; i < 100; i++) {
                    sum2 += i;
                }
                return sum2;
            }
        });
        // 3.获取结果
        Integer integer1 = future1.get();
        Integer integer2 = future2.get();

        System.out.println("结果是:" + (integer1 + integer2));
        // 4.关闭线程池
        pool.shutdown();
    }
}

在这里插入图片描述

三、线程的状态

在这里插入图片描述

①:休眠 (sleep)

package com.example.d8_threadStatus;

public class SleepThread implements Runnable{
    @Override
    public void run() {
        for (int i = 0; i < 10; i++) {
            System.out.println("线程名称: " + Thread.currentThread().getName() + ".........." + i);
            try {
                Thread.sleep(1000); // sleep异常不也能直接抛出
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}
package com.example.d8_threadStatus;

public class TestSleep {
    public static void main(String[] args) {
        SleepThread s1 = new SleepThread();
        new Thread(s1).start();

        SleepThread s2 = new SleepThread();
        new Thread(s1).start();
    }
}

在这里插入图片描述

②:放弃 (yield)

package com.example.d8_threadStatus;

public class YieldThread implements Runnable{
    @Override
    public void run() {
        for (int i = 0; i < 10; i++) {
            System.out.println("线程名称:" + Thread.currentThread().getName() + ".........." + i);
            Thread.yield();
        }
    }
}
package com.example.d8_threadStatus;

public class TestYield {
    public static void main(String[] args) {
        new Thread(new YieldThread()).start();
        new Thread(new YieldThread()).start();
    }
}

在这里插入图片描述

③:加入(join)

package com.example.d8_threadStatus;

public class JoinThread extends Thread{
    @Override
    public void run() {
        for (int i = 0; i < 50; i++) {
            System.out.println("线程名称: " + Thread.currentThread().getName() + ".........." + i);
            try {
                Thread.sleep(100);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}
package com.example.d8_threadStatus;

public class TestJoin {
    public static void main(String[] args) {
        JoinThread joinThread = new JoinThread();
        joinThread.start();

        for (int i = 0; i < 50; i++) {
            System.out.println("main........." + i);
            try {
                Thread.sleep(100);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }

    }
}

在这里插入图片描述

使用Join 加入线程的情况如下

在这里插入图片描述

④:修改线程优先级(priority)

在这里插入图片描述

package com.example.d8_threadStatus;

public class PriorityThread extends Thread{
    @Override
    public void run() {
        for (int i = 0; i < 50; i++) {
            System.out.println(Thread.currentThread().getName() + "=================="+i);
        }
    }
}

package com.example.d8_threadStatus;

public class TestPriority {
    public static void main(String[] args) {
        // 创建线程
        PriorityThread p1 = new PriorityThread();
        p1.setName("p1");
        PriorityThread p3 = new PriorityThread();
        p3.setName("p3");
        // 设置优先级
        p1.setPriority(1);
        p3.setPriority(10);
        // 启动
        p1.start();
        p3.start();

    }
}

在这里插入图片描述

⑤:守护线程(Daemon)

在这里插入图片描述

package com.example.d8_threadStatus;

public class DeamonThread extends Thread{
    @Override
    public void run() {
        for (int i = 0; i < 50; i++) {
            System.out.println(Thread.currentThread().getName() + "=========" + i);
            try {
                Thread.sleep(100);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}

package com.example.d8_threadStatus;

public class TestDeamon {
    public static void main(String[] args) {
        DeamonThread d1 = new DeamonThread();
        d1.setName("d1");
        d1.setDaemon(true);
        d1.start();
        for (int i = 0; i < 10; i++) {
            System.out.println("main............" + i);
            try {
                Thread.sleep(100);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}

在这里插入图片描述

⑥:线程状态(等待)

在这里插入图片描述在这里插入图片描述在这里插入图片描述

四、线程安全

①:线程安全问题

在这里插入图片描述

package com.example.d8_threadStatus;
import java.util.Arrays;
public class Test {
    private static int index = 0;

    public static void main(String[] args) throws InterruptedException {
        String[] s = new String[5];
        Runnable r1 = new Runnable() {
            @Override
            public void run() {
                s[index] = "hello";
                index++;
            }
        };
        Runnable r2 = new Runnable() {
            @Override
            public void run() {
                s[index] = "word";
                index++;
            }
        };

        Thread a = new Thread(r1, "r1");
        Thread b = new Thread(r2, "r2");
        a.start();
        b.start();
        // 加入线程保证a b 两个线程执行完
        a.join();
        b.join();
        System.out.println(Arrays.toString(s));
    }
}

在这里插入图片描述

②:同步代码块

01.方式一:

在这里插入图片描述
在这里插入图片描述

1.解决买票问题
package com.example.d7_runnableDemo;

public class Ticket implements Runnable{
    private static int ticketNum = 100;
    // 创建锁
    private Object object = new Object();
    @Override
    public void run() {

        while (true) {
            synchronized (object){
                if (ticketNum <= 0){
                    break;
                }
                System.out.println("线程名称:" + Thread.currentThread().getName() + (101 - ticketNum));
                ticketNum --;
            }
        }

    }
}

package com.example.d7_runnableDemo;

public class TestTicket {
    public static void main(String[] args) {
        Ticket ticket = new Ticket();
        Thread thread = new Thread(ticket,"窗口1 ");
        Thread thread2 = new Thread(ticket,"窗口2 ");
        Thread thread3 = new Thread(ticket,"窗口3 ");
        Thread thread4 = new Thread(ticket,"窗口4 ");
        thread.start();
        thread2.start();
        thread3.start();
        thread4.start();
    }
}

在这里插入图片描述

在这里插入图片描述
在这里插入图片描述

2.解决存取钱问题
package com.example.d7_runnableDemo;

public class TestBankCard2 {
    public static void main(String[] args) {
        BankCard bankCard = new BankCard();
        // 存钱
        Runnable add = new Runnable() {
            @Override
            public void run() {
                for (int i = 0; i < 10; i++) {
                    synchronized (bankCard){
                        bankCard.setMoney(bankCard.getMoney() + 1000);
                        System.out.println(Thread.currentThread().getName() + "存了1000元"+ " 余额为:" +bankCard.getMoney()+"元~");
                    }
                }
            }
        };
        // 取钱
        Runnable sub = new Runnable() {
            @Override
            public void run() {
                for (int i = 0; i < 10; i++) {
                    synchronized (bankCard){
                        if (bankCard.getMoney() >= 1000){
                            bankCard.setMoney(bankCard.getMoney() - 1000);
                            System.out.println(Thread.currentThread().getName() + "取了1000元"+ " 余额为:" +bankCard.getMoney()+"元!");
                        }else {
                            System.out.println("余额不足,赶快存钱。。。。。");
                            i--;
                        }
                    }
                }
            }
        };

        new Thread(add,"小白 ").start();
        new Thread(sub,"小美 ").start();
    }
}

在这里插入图片描述

02. 方式二:(同步方法)

在这里插入图片描述

package com.example.d7_runnableDemo;

public class Ticket implements Runnable{
    private static int ticketNum = 100;
    // 创建锁
    private Object object = new Object();
    @Override
    public void run() {

        while (true) {
            if (!tick()){
                break;
            }
        }
    }
    public synchronized boolean tick(){
        if (ticketNum <= 0){
            return false;
        }
        System.out.println("线程名称:" + Thread.currentThread().getName() + (101 - ticketNum));
        ticketNum --;
        return true;
    }
}

在这里插入图片描述

③:同步规则

在这里插入图片描述

④:死锁

package com.example.d9_lock;

public class MyLock {
    public static Object a = new Object();
    public static Object b = new Object();
}

package com.example.d9_lock;

public class TestLock {
    public static void main(String[] args) {
        Boy boy = new Boy();
        Girl girl = new Girl();
        boy.start();
        girl.start();
    }
}

package com.example.d9_lock;

public class Boy extends Thread{
    @Override
    public void run() {
        synchronized (MyLock.a){
            System.out.println("男孩拿到了a");
            synchronized (MyLock.b){
                System.out.println("男孩拿到了b");
                System.out.println("可以开始吃了");
            }
        }
    }
}

package com.example.d9_lock;

public class Girl extends Thread{
    @Override
    public void run() {
        synchronized (MyLock.b){
            System.out.println("女孩拿到了b");
            synchronized (MyLock.a){
                System.out.println("女孩拿到了a");
                System.out.println("可以开始吃了");
            }
        }
    }
}

在这里插入图片描述
在这里插入图片描述

⑤:线程通信

在这里插入图片描述

package com.example.d9_lock;

public class AddAndSubMoney {
    public static boolean flag = false;
    public static  BankCard bankCard = new BankCard();
    private static AddAndSubMoney addAndSubMoney = new AddAndSubMoney();
    // 存钱
    public synchronized void sub1(){
        while (!flag){ // false 没有钱
            try {
                this.wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        bankCard.setMoney(bankCard.getMoney() - 1000);
        System.out.println(Thread.currentThread().getName() + "取了1000元,余额是"+bankCard.getMoney());
        // 修改标记
        flag = false;
        // 唤醒存钱线程
        this.notifyAll();
    }
    // 取钱
    public synchronized void save(){
        while (flag){ // true 有钱
            try {
                this.wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        bankCard.setMoney(bankCard.getMoney() + 1000);
        System.out.println(Thread.currentThread().getName() + "存了1000元,余额是"+bankCard.getMoney());
        // 修改标记
        flag = true;
        // 唤醒取钱线程
        this.notifyAll();
    }

    public static void main(String[] args) {
        Runnable add = new Runnable() {
            @Override
            public void run() {
                for (int i = 0; i < 10; i++) {
                    addAndSubMoney.save();
                }
            }
        };
        Runnable sub = new Runnable() {
            @Override
            public void run() {
                for (int i = 0; i < 10; i++) {
                    addAndSubMoney.sub1();
                }
            }
        };
        new Thread(sub,"小白").start();
        new Thread(add,"小黑").start();
        new Thread(sub,"小华").start();
        new Thread(add,"小明").start();
    }
}

在这里插入图片描述

经典问题(生产者 消费者)

在这里插入图片描述

package com.example.d9_lock;

public class ProductionAndConsumeBread {
    private static ProductionAndConsumeBread p = new ProductionAndConsumeBread();
    // 存放面包的数组
    private static Bread[] breads = new Bread[6];
    // 存放面包的位置
    private static int index = 0;
    // 存放面包
    public  synchronized void intBread(Bread bread){
        // 判断容器有没有满
        if (index >= breads.length){
            // 满了,加入队列
            try {
                this.wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        breads[index] = bread;
        System.out.println(Thread.currentThread().getName() + "存了一个面包,剩余面包 "+(index + 1) + " 个");
        index ++;
        this.notifyAll();
    }

    // 取出面包
    public synchronized void outBread(){
        // 判断容器是否还有面包
        if (index <= 0){
            // 没有面包
            try {
                this.wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        breads[index - 1] = null;
        System.out.println(Thread.currentThread().getName() + "取了一个面包,剩余面包 "+(index -1) + " 个");
        index --;
        this.notifyAll();
    }

    public static void main(String[] args) {
        Runnable add = new Runnable() {
            @Override
            public void run() {
                for (int i = 0; i < 10; i++) {
                    p.intBread(new Bread(i,Thread.currentThread().getName()));
                }
            }
        };
        Runnable out = new Runnable() {
            @Override
            public void run() {
                for (int i = 0; i < 10; i++) {
                    p.outBread();
                }
            }
        };

        new Thread(add,"小虎").start();
        new Thread(out,"小白").start();
    }


}

在这里插入图片描述

⑥:小结

在这里插入图片描述

五、线程池

①:线程池概念

在这里插入图片描述

原理

在这里插入图片描述

②:创建线程池

在这里插入图片描述在这里插入图片描述
在这里插入图片描述

package com.example.d10_executor;

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class CreateExecutor {
    public static void main(String[] args) {

        // 1.创建线程池
        ExecutorService pool = Executors.newFixedThreadPool(5);
        // 2.创建任务
        final int[] index = {0};
        Runnable runnable = new Runnable() {
            @Override
            public void run() {
               while (true){
                       if (index[0] >= 100){
                           break;
                       }
                       System.out.println(Thread.currentThread().getName() + "卖了第" + (index[0] + 1) + "张票");
                       index[0]++;
               }
            }
        };
        // 3.将任务提交给线程池
        for (int i = 0; i < 4; i++) {
            pool.submit(runnable);
        }
        // 4. 关闭线程池
        pool.shutdown(); // 等待任务所有执行完毕然后关闭线程池
       // pool.shutdownNow(); // 不等待任务执行完毕就会关闭线程池
    }
}

在这里插入图片描述

③:Future接口

在这里插入图片描述## ④:异步和同步

同步:

在这里插入图片描述

异步:

在这里插入图片描述

六、Lock接口

①:重入锁

在这里插入图片描述

package com.example.d9_lock;

import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

class ReentrantLock2 {
    private Lock lock = new ReentrantLock();
    private String[] strs = {"A","B","","",""};
    private int count = 2;
    public void add(String str){
        lock.lock(); // 开启锁
        try {
            strs[count] = str;
            count++;
            System.out.println(Thread.currentThread().getName() + "添加了元素" + str);
        }finally {
            lock.unlock(); // 释放锁
        }
    }


    public String[] getStrs() {
        return strs;
    }
}

package com.example.d9_lock;

import java.util.Arrays;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class MyLock2 {
    private static ReentrantLock2 rl = new ReentrantLock2();
    public static void main(String[] args) {
        // 创建线程池对象
        ExecutorService pool = Executors.newFixedThreadPool(2);

        pool.submit(new Runnable() {
            @Override
            public void run() {
                rl.add("Word");
            }
        });
        pool.submit(new Runnable() {
            @Override
            public void run() {
                rl.add("Hello");
            }
        });

        pool.shutdown();

        String[] strs = rl.getStrs();
        System.out.println(Arrays.toString(strs));
    }
}

在这里插入图片描述

②:使用Lock完成窗口买票

方法一:

package com.example.d9_lock;

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

public class TicketLock {
    private static MyLock3 myLock3 = new MyLock3();

    public static void main(String[] args) {
        // 创建线程池
        ExecutorService pool = Executors.newFixedThreadPool(4);
        // 提交任务
        for (int i = 0; i < 4; i++) {
            pool.submit(myLock3);
        }
        // 关闭线程池
        pool.shutdown();
    }
}

class MyLock3 implements Runnable {
    private static Lock lock = new ReentrantLock();
    private static int number = 0;

    @Override
    public void run() {
        while (true) {
            lock.lock(); // 开启锁
            try {
                if (number >= 1000){
                   break;
                }
                System.out.println(Thread.currentThread().getName() + "卖了第" + (number + 1) + "张票");
                number++;
            } finally {
                lock.unlock(); //释放锁
            }
        }
    }
}

方法二:

package com.example.d9_lock;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
public class TicketLock2 {
    private static TicketLock2 ticketLock2 = new TicketLock2();
    private static Lock lock = new ReentrantLock();
    private static int number = 0;

    public void ticket(){
        while (true) {
            lock.lock(); // 开启锁
            try {
                if (number >= 1000){
                    break;
                }
                System.out.println(Thread.currentThread().getName() + "卖了第" + (number + 1) + "张票");
                number++;
            } finally {
                lock.unlock(); //释放锁
            }
        }
    }

    public static void main(String[] args) {
        // 创建线程池
        ExecutorService pool = Executors.newFixedThreadPool(4);
        // 提交任务
        for (int i = 0; i < 4; i++) {
            pool.submit(new Runnable() {
                @Override
                public void run() {
                    ticketLock2.ticket();
                }
            });
        }
        // 关闭线程池
        pool.shutdown();
    }
}

在这里插入图片描述

③:读写锁

在这里插入图片描述

01.使用读写锁

package com.example.readAndWirteLock;

import java.util.concurrent.locks.ReentrantReadWriteLock;
import java.util.concurrent.locks.ReentrantReadWriteLock.ReadLock;
import java.util.concurrent.locks.ReentrantReadWriteLock.WriteLock;

public class ReadWriteDemo {
    // 创建读写锁
    ReentrantReadWriteLock rwl = new ReentrantReadWriteLock();
    // 获取读锁
    private ReadLock readLock = rwl.readLock();
    // 获取写锁
    private WriteLock writeLock = rwl.writeLock();
    private String value;

    // 读锁
    public String getValue(){
        readLock.lock();
        try {
            try {
                Thread.sleep(100);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("读取:" + value);
            return this.value;
        }finally {
            readLock.unlock();
        }

    }

    // 写锁
    public void setValue(String value){
        writeLock.lock();
        try{
            try {
                Thread.sleep(100);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("写入:" + value);
            this.value = value;
        }finally {
            writeLock.unlock();
        }
    }
}

package com.example.readAndWirteLock;

import java.util.Random;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class ReadWriteTest {
    private static Random random = new Random();
    public static void main(String[] args) {
        Long start = System.currentTimeMillis();
        ReadWriteDemo readWriteDemo = new ReadWriteDemo();
        // 创建线程池
        ExecutorService pool = Executors.newFixedThreadPool(200);

        // 分配20个写操作
        for (int i = 0; i < 20; i++) {
            pool.submit(new Runnable() {
                @Override
                public void run() {
                    readWriteDemo.setValue("小黑: " + random.nextInt(1000));
                }
            });
        }

        // 分配180个读操作
        for (int i = 0; i < 180; i++) {
            pool.submit(new Runnable() {
                @Override
                public void run() {
                    readWriteDemo.getValue();
                }
            });
        }

        // 关闭线程池
        pool.shutdown();

        while (!pool.isTerminated()){

        }
        Long end = System.currentTimeMillis();
        System.out.println("使用读写锁用时:" + (end - start));


    }
}

在这里插入图片描述

02.不使用读写锁

package com.example.readAndWirteLock;

import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

public class ReadWriteDemo {
    private static Lock lock = new ReentrantLock();
    private String value;

    // 读锁
    public String getValue(){
        lock.lock();
        try {
            try {
                Thread.sleep(100);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("读取:" + value);
            return this.value;
        }finally {
            lock.unlock();
        }
    }

    // 写锁
    public void setValue(String value){
        lock.lock();
        try{
            try {
                Thread.sleep(100);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("写入:" + value);
            this.value = value;
        }finally {
            lock.unlock();
        }
    }
}

package com.example.readAndWirteLock;

import java.util.Random;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class ReadWriteTest {
    private static Random random = new Random();
    public static void main(String[] args) {
        Long start = System.currentTimeMillis();
        ReadWriteDemo readWriteDemo = new ReadWriteDemo();
        // 创建线程池
        ExecutorService pool = Executors.newFixedThreadPool(200);

        // 分配20个写操作
        for (int i = 0; i < 20; i++) {
            pool.submit(new Runnable() {
                @Override
                public void run() {
                    readWriteDemo.setValue("小黑: " + random.nextInt(1000));
                }
            });
        }

        // 分配180个读操作
        for (int i = 0; i < 180; i++) {
            pool.submit(new Runnable() {
                @Override
                public void run() {
                    readWriteDemo.getValue();
                }
            });
        }

        // 关闭线程池
        pool.shutdown();

        while (!pool.isTerminated()){

        }
        Long end = System.currentTimeMillis();
        System.out.println("不使用读写锁用时:" + (end - start));


    }
}

在这里插入图片描述

七、线程安全的集合

在这里插入图片描述
在这里插入图片描述

①:问题演示

package com.example.arrays;

import java.util.ArrayList;

public class Demo1 {
    public static void main(String[] args) {
        // 1.创建arrayList
        ArrayList<String> arrayList = new ArrayList<>();
        // 2.创建线程
        for (int i = 0; i < 20; i++) {
            int temp = i;
            new Thread(new Runnable() {
                @Override
                public void run() {
                    for (int i1 = 0; i1 < 10; i1++) {
                        arrayList.add(Thread.currentThread().getName() + "==" + temp);
                        System.out.println(arrayList.toString());
                    }
                }
            }).start();
        }
    }
}

在这里插入图片描述

②:使用Collections中的工具类

在这里插入图片描述在这里插入图片描述
在这里插入图片描述

③: 使用CopyOnWriteArrayList

在这里插入图片描述

案例1

package com.example.arrays;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.stream.Collectors;

public class Demo1 {
    public static void main(String[] args) {
        // 1.创建CopyOnWriteArrayList
        CopyOnWriteArrayList<String> list = new CopyOnWriteArrayList<>();
        // 2.创建线程
        for (int i = 0; i < 20; i++) {
            int temp = i;
            new Thread(new Runnable() {
                @Override
                public void run() {
                    for (int i1 = 0; i1 < 10; i1++) {
                        list.add(Thread.currentThread().getName() + "==" + temp);
                        System.out.println(list.toString());
                    }
                }
            }).start();
        }
    }
}

在这里插入图片描述

案例2

package com.example.arrays;

import java.util.Random;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class Demo2 {
    public static void main(String[] args) {
        // 创建集合
        CopyOnWriteArrayList<String> list = new CopyOnWriteArrayList<>();
        // 创建线程池
        ExecutorService pool = Executors.newFixedThreadPool(5);
        // 创建任务
        for (int i = 0; i < 5; i++) {
            pool.submit(new Runnable() {
                @Override
                public void run() {
                    for (int i1 = 0; i1 < 10; i1++) {
                        String str = Thread.currentThread().getName() + new Random().nextInt(100);
                        list.add(str);
                        System.out.println(str);
                    }
                }
            });
        }

        // 关闭线程池
        pool.shutdown();

        while (!pool.isTerminated()){}
        System.out.println("集合大小为:"+list.size());
    }
}

在这里插入图片描述

④:CopyOnWriteArraySet

在这里插入图片描述

package com.example.arrays;

import java.util.concurrent.CopyOnWriteArraySet;

public class Demo3 {
    public static void main(String[] args) {
        CopyOnWriteArraySet<String> list = new CopyOnWriteArraySet<>();
        list.add("A");
        list.add("B");
        list.add("C");
        list.add("D");
        list.add("A");
        System.out.println("元素个数:"+list.size());
        System.out.println(list.toString());


    }
}

在这里插入图片描述

⑤:Queue接口(队列)

在这里插入图片描述

package com.example.arrays;

import java.util.LinkedList;
import java.util.Queue;

public class Demo4 {
    public static void main(String[] args) {
        // 创建集合
        Queue<String> queue = new LinkedList<>();
        // 添加元素
        queue.add("苹果");
        queue.add("香蕉");
        queue.add("葡萄");
        queue.add("橘子");
        queue.add("榴莲");
        // 获取第一个元素不删除
        System.out.println(queue.peek());
        System.out.println("======================");
        System.out.println("元素个数为:"+queue.size());
        int size = queue.size();
        for (int i = 0; i < size; i++) {
            System.out.println(queue.poll()); // 出队
        }
        System.out.println("元素个数为:"+queue.size()); // 出队后元素个数为0
    }
}

在这里插入图片描述

⑥:ConcurrentLinkedQueue的使用

在这里插入图片描述

package com.example.arrays;

import java.util.concurrent.ConcurrentLinkedDeque;

public class Demo5 {
    public static void main(String[] args) throws InterruptedException {
        // 创建集合
        ConcurrentLinkedDeque<Integer> deque = new ConcurrentLinkedDeque<>();
        // 创建任务
        Thread t1 = new Thread(new Runnable() {
            @Override
            public void run() {
                for (int i = 0; i <= 5; i++) {
                    deque.offer(i);
                }
            }
        });
        Thread t2 = new Thread(new Runnable() {
            @Override
            public void run() {
                for (int i = 6; i <= 10; i++) {
                    deque.offer(i);
                }
            }
        });
        // 启动线程
        t1.start();
        t2.start();

        t1.join();
        t2.join();
        System.out.println("----------出队----------");
        int size = deque.size();
        for (int i = 0; i < size; i++) {
            System.out.println(deque.poll());
        }
    }
}

在这里插入图片描述

⑦:BlockingQueue接口(阻塞队列)

在这里插入图片描述在这里插入图片描述> 案例1:

package com.example.arrays;

import java.util.concurrent.ArrayBlockingQueue;

public class Demo6 {
    public static void main(String[] args) throws InterruptedException {
        // 创建一个有界队列,添加元素
        ArrayBlockingQueue<String> queue = new ArrayBlockingQueue<>(5);

        // 添加元素
        queue.put("a");
        queue.put("b");
        queue.put("c");
        queue.put("d");
        queue.put("e");
        System.out.println("已经添加了5个元素~");
        queue.put("f");
        System.out.println("已经添加了6个元素~");
    }
}

在这里插入图片描述
在这里插入图片描述

案例2 生产者和消费者

package com.example.arrays;

import java.util.concurrent.ArrayBlockingQueue;

public class Demo7 {
    public static void main(String[] args) {
        // 创建线程
        ArrayBlockingQueue<Integer> queue = new ArrayBlockingQueue<>(6);
        // 创建两个线程
        Thread t1 = new Thread(new Runnable() {
            @Override
            public void run() {
                for (int i = 0; i < 30; i++) {
                    try {
                        queue.put(i);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    System.out.println(Thread.currentThread().getName() + "生产了第 " + i + "块面包");
                }
            }
        }, "小黑");

        Thread t2 = new Thread(new Runnable() {
            @Override
            public void run() {
                for (int i = 0; i < 30; i++) {
                    try {
                        queue.take();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    System.out.println(Thread.currentThread().getName() + "消费了第 " + i + "块面包");
                }
            }
        }, "小白");

        // 启动线程
        t1.start();
        t2.start();
    }
}

在这里插入图片描述

⑧:ConcurrentHashMap 线程安全集合

在这里插入图片描述

package com.example.arrays;

import java.util.concurrent.ConcurrentHashMap;

public class Demo8 {
    public static void main(String[] args) {
        // 创建集合
        ConcurrentHashMap<String,Integer> hashMap = new ConcurrentHashMap<>();
        // 使用多线程添加数据
        for (int i = 0; i < 6; i++) {
            new Thread(new Runnable() {
                @Override
                public void run() {
                    for (int j = 0; j < 10; j++) {
                        hashMap.put(Thread.currentThread().getName(),j);
                        System.out.println(hashMap);
                    }
                }
            }).start();
        }
    }
}

在这里插入图片描述

⑨:总结

在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

七@归七

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值