21_多线程

时间:2021-03-09 09:22:03   收藏:0   阅读:28

1. 什么是进程

2. 什么是线程

3. 进程和线程的区别

  1. 进程是操作系统资源分配的基本单位, 而线程是CPU的基本调度单位
  2. 一个程序运行后至少有一个进程
  3. 一个进程可以包含多个线程, 但是至少需要有一个线程, 否则这个进程是没有意义的
  4. 进程间不能共享数据段地址, 但同进程的线程之间可以

4. 线程的组成

5. 线程的特点

  1. 线程抢占式执行
    • 效率高
    • 可防止单一线程长时间独占CPU
  2. 在单核CPU中, 宏观上同时执行, 微观上顺序执行

6. 创建线程

方式一: 继承Thread类, 重写run方法

package com.thread.demo01;

public class MyThread extends Thread {
    
    public MyThread() {
    }

    public MyThread(String name) {
        super(name);
    }
    
    @Override
    public void run() {
        for (int i = 0; i < 100; i++) {
            //方式一: this.getId()获取线程Id,this.getName()获取线程名称
            //System.out.println("线程id: " + this.getId() + " 线程名称: " + this.getName() + " 子线程:......" +i);
            //方式二(推荐): Thread.currentThread() 获取当前线程
            System.out.println("线程id: " + Thread.currentThread().getId() + " 线程名称: " + Thread.currentThread().getName() + " 子线程:......" + i);
        }
    }
}

启动多个线程

package com.thread.demo01;
public class TestThread {

    public static void main(String[] args) {

        //1. 创建线程对象
        MyThread myThread = new MyThread("我的子线程1");
        //2. 启动线程,不能用run()方法
        //myThread.setName("我的子线程1"); //启动线程前设置线程名称
        myThread.start();
        System.out.println(myThread.getId());

        MyThread myThread1 = new MyThread("我的子线程2);
        //myThread1.setName("我的子线程2"); //启动线程前设置线程名称
        myThread1.start();
        System.out.println(myThread1.getId());

        //主线程执行
        for (int i = 0; i < 50; i++) {
            System.out.println("主线程:......" + i);
        }
    }
}
案例一: 实现四个窗口同时各卖票100张
public class SellTicket extends Thread{

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

    private int ticket = 100;//票

    @Override
    public void run() {
        while (ticket > 0) {
            System.out.println(Thread.currentThread().getName() + "卖的第" + (101 - ticket) + "张票");
            ticket--;
        }
    }
}
public class TestTicket {

    public static void main(String[] args) {

        //1. 创建四个卖票窗口
        SellTicket st1 = new SellTicket("窗口一");
        SellTicket st2 = new SellTicket("窗口二");
        SellTicket st3 = new SellTicket("窗口三");
        SellTicket st4 = new SellTicket("窗口四");

        //2. 开启多线程
        st1.start();
        st2.start();
        st3.start();
        st4.start();




    }
}

方式二: 实现Runnable接口

Thread的构造方法,可传入Runnable target, String name ,即Runnable接口类型的对象和字符串类型的名称

private void init(ThreadGroup g, Runnable target, String name,
                  long stackSize, AccessControlContext acc,
                  boolean inheritThreadLocals)
public class MyRunnable implements Runnable{


    @Override
    public void run() {
        for (int i = 0; i < 100; i++) {
            System.out.println(Thread.currentThread().getName() + "子线程......" + i);
        }
    }
}
public class TestRunnable {

    public static void main(String[] args) {

        //创建MyRunnable对象, 表示线程要执行的功能
        MyRunnable runnable = new MyRunnable();

        //2. 创建线程对象
        Thread thread = new Thread(runnable, "我的线程一");
        Thread thread1 = new Thread(runnable, "我的线程二");

        //3. 启动多线程
        thread.start();
        thread1.start();

        for (int i = 0; i < 50; i++) {
            System.out.println("主线程" + i);
        }
    }
}

方式二优化: 使用匿名内部类

public class TestRunnable1 {

    public static void main(String[] args) {

        //1. 创建Runnable对象, 以及使用匿名内部类
        Runnable runnable = new Runnable() {
            @Override
            public void run() {
                for (int i = 0; i < 100; i++) {
                    System.out.println(Thread.currentThread().getName() + "子线程......" + i);
                }
            }
        };

        //2. 创建线程对象
        Thread thread = new Thread(runnable, "我的线程1");
        Thread thread1 = new Thread(runnable, "我的线程2");

        //3. 启动多线程
        thread.start();
        thread1.start();

        for (int i = 0; i < 50; i++) {
            System.out.println("主线程" + i);
        }

    }
    
}
案例二: 实现四个窗口共同卖票100张
public class Ticket implements Runnable{

    private int ticket = 100;


    @Override
    public void run() {
        while (ticket > 0){
            System.out.println(Thread.currentThread().getName() + "售出第" + (101-ticket) + "张票");
            ticket--;
        }

    }
    
}
public class TestTicket {

    public static void main(String[] args) {

        Ticket ticket = new Ticket();

        Thread wd1 = new Thread(ticket, "窗口一: ");
        Thread wd2 = new Thread(ticket, "窗口二: ");
        Thread wd3 = new Thread(ticket, "窗口三: ");
        Thread wd4 = new Thread(ticket, "窗口四: ");

        wd1.start();
        wd2.start();
        wd3.start();
        wd4.start();
    }
}
案例三: 实现两人共用一张银行卡, 一人存钱, 另一人取钱
public class BankCard {//创建银行卡类

    private double money;//余额

    public double getMoney() {
        return money;
    }

    public void setMoney(double money) {
        this.money = money;
    }
}
public class AddMoney implements Runnable{//创建存钱类, 实现Runnable接口

    private BankCard card;

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

    @Override
    public void run() {
        for (int i = 0; i < 10; i++) {
            card.setMoney(card.getMoney() + 1000);
            System.out.println(Thread.currentThread().getName() + "存的第" + (i+1) + "笔钱,金额为1000元, 现卡上余额: " + card.getMoney() + "元");
        }

    }
}
public class SubMoney implements Runnable{//创建取钱类, 实现Runnable接口

    private BankCard card;

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

    @Override
    public void run() {
        for (int i = 0; i < 10; i++) {
            if (card.getMoney() >= 1000){
                card.setMoney(card.getMoney() - 1000);
                System.out.println(Thread.currentThread().getName() + "取了第" + (i+1) + "笔钱,金额为1000元, 现卡上余额: " + card.getMoney() + "元");
            }else{
                System.out.println("余额不足...");
                i--;
            }
        }

    }
}
public class TestBankCard {

    public static void main(String[] args) {

        //1. 创建银行卡对象
        BankCard card = new BankCard();

        //2. 创建存钱对象
        AddMoney addMoney = new AddMoney(card);
        //3. 创建取钱对象
        SubMoney subMoney = new SubMoney(card);

        //4. 创建两个线程
        Thread boy = new Thread(addMoney, "男孩");
        Thread girl = new Thread(subMoney, "女孩");

        //5. 开启线程
        boy.start();
        girl.start();



    }
}

7. 线程的状态

(1) 基本
  1. New(新创建): 线程对象被创建, 即为新创建状态. 只在堆中开辟内存, 与常规对象无异
  2. Runnable(可运行): 调用start()后进入可运行状态, 等待被OS选中并分配时间片后开始运行, 时间片到期后又重新进入可运行状态,等待被OS选中
  3. Terminated(终止状态): 主线程main()或独立线程run()结束, 进入终止状态, 并释放持有的时间片
    • 正常终止: run()方法正常退出
    • 意外终止: 因为一个没有捕获的异常终止了run()方法
(2) 阻塞

技术分享图片

8. 常见方法

(1)sleep()方法 休眠

public class SleepThread extends Thread{

    @Override
    public void run() {
        for (int i = 0; i < 10; i++) {
            System.out.println(Thread.currentThread().getName() + "--------------" + i);
            try {
                SleepThread.sleep(2000);//睡眠两秒钟
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}
public class TestSleep {

    public static void main(String[] args) {

        SleepThread s1 = new SleepThread();
        SleepThread s2 = new SleepThread();

        s1.start();
        s2.start();
    }
}

(2)yield()方法 让步

public class YieldThread extends Thread{

    @Override
    public void run() {
        for (int i = 0; i < 10; i++) {
            System.out.println(Thread.currentThread().getName() + "-------------" + i);
            //放弃CPU
            YieldThread.yield();
        }
    }
}
public class TestYield {

    public static void main(String[] args) {

        YieldThread y1 = new YieldThread();
        YieldThread y2 = new YieldThread();

        y1.start();
        y2.start();
    }   
}

(3)join()方法 加入

public class JoinThread extends Thread{

    @Override
    public void run() {
        for (int i = 0; i < 20; i++) {
            System.out.println(Thread.currentThread().getName() + "子线程------------" + i);
            try {
                JoinThread.sleep(500);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}
public class TestJoin {

    public static void main(String[] args) {

        JoinThread j1 = new JoinThread();
        j1.start();
        try {
            j1.join();//加入到当前线程main, 并阻塞当前线程main, 直到加入的线程j1执行完毕
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        //主线程
        for (int i = 0; i < 30; i++) {
            System.out.println(Thread.currentThread().getName() + "主线程: " + i);
            try {
                Thread.sleep(100);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}

(4)优先级 Priority

public class PriorityThread extends Thread{

    @Override
    public void run() {
        for (int i = 0; i < 20; i++) {
            System.out.println(Thread.currentThread().getName() + "子线程:------ " + i);
        }
    }
}
public class TestPriority {

    public static void main(String[] args) {

        PriorityThread p1 = new PriorityThread();
        p1.setName("p1");
        PriorityThread p2 = new PriorityThread();
        p2.setName("p2");
        PriorityThread p3 = new PriorityThread();
        p3.setName("p3");
        p1.start();
        p2.start();
        p3.start();
        p1.setPriority(1);//优先级最低
        p2.setPriority(3);
        p3.setPriority(10);//优先级最高


        for (int i = 0; i < 20; i++) {
            System.out.println(Thread.currentThread().getName() + "主线程:------ " + i);
        }
    }
}

(5)守护线程 Daemon

public class DaemonThread extends Thread{

    @Override
    public void run() {
        for (int i = 0; i < 20; i++) {
            System.out.println("子线程: " + Thread.currentThread().getName() + "-----------" + i);
            try {
                Thread.sleep(500);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}
public class TestDaemon {

    public static void main(String[] args) {

        //1. 创建线程(默认为前台线程)
        DaemonThread d1 = new DaemonThread();
        //2. 设置为守护线程(后台线程) 当主线程执行完毕后,守护线程(后台线程)会自动结束
        d1.setDaemon(true);
        d1.start();


        for (int i = 0; i < 10; i++) {
            System.out.println("主线程: " + Thread.currentThread().getName() + "-------" + i);
            try {
                Thread.sleep(200);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }


}

9. 线程安全

(1) 同步方式1

import java.util.Arrays;

public class ThreadSafe {

    private static int index = 0;
    public static void main(String[] args) throws InterruptedException {

        //1. 创建数组
        String[] s = new String[5];

        //2. 创建两个操作
        Runnable runnableA = new Runnable() {
            @Override
            public void run() {
                //同步代码块
                synchronized (s){
                    s[index] = "hello";
                    index++;
                }
            }
        };
        Runnable runnableB = new Runnable() {
            @Override
            public void run() {
                //同步代码块
                synchronized (s){
                    s[index] = "world";
                    index++;
                }
            }
        };
        //3. 创建两个线程
        Thread thread1 = new Thread(runnableA, "A");
        Thread thread2 = new Thread(runnableB, "B");
        //4. 启动
        thread1.start();
        thread2.start();
        //5. 加入线程
        thread1.join();
        thread2.join();

        System.out.println(Arrays.toString(s));
    }
}
优化案例二(1): 使用同步代码块

实现四个窗口共同卖票100张, 不能出现四个窗口同时卖出一张票的情况

public class Ticket implements Runnable{

    private int ticket = 100;//票
    //创建锁
    //private Object obj = new Object();


    @Override
    public void run() {
        while (true){
            synchronized (this){//this---当前对象,这里放入obj和this都可以
                if (ticket <= 0){
                    break;
                }
                System.out.println(Thread.currentThread().getName() + "卖的第" + (101-ticket) + "张票");
                ticket--;
            }

        }
    }
}
public class TestSafeTicket {

    public static void main(String[] args) {

        //1. 创建票对象
        Ticket ticket = new Ticket();

        //2. 创建四个线程对象
        Thread win1 = new Thread(ticket, "窗口一");
        Thread win2 = new Thread(ticket, "窗口二");
        Thread win3 = new Thread(ticket, "窗口三");
        Thread win4 = new Thread(ticket, "窗口四");

        //3. 启动
        win1.start();
        win2.start();
        win3.start();
        win4.start();

    }
}
优化案例三: 使用同步代码块

两人用同一张银行卡,一人存钱,另一人取钱, 不能出现存钱后卡上没钱或卡上没钱还能取出的情况

public class BankCard {

    private double money;//余额

    public double getMoney() {
        return money;
    }

    public void setMoney(double money) {
        this.money = money;
    }
}
public class TestBank {

    public static void main(String[] args) {

        //1. 创建银行卡对象
        BankCard bankCard = new BankCard();

        //2. 创建存钱取钱操作
        Runnable addMoney = new Runnable() {
            @Override
            public void run() {
                for (int i = 1; i <= 10; i++) {
                    synchronized (bankCard){
                        bankCard.setMoney(bankCard.getMoney() + 1000);
                        System.out.println(Thread.currentThread().getName() + "第" + i + "次存了1000元" + "现卡上余额: " + bankCard.getMoney());
                    }

                }

            }
        };
        Runnable subMoney = new Runnable() {
            @Override
            public void run() {
                for (int i = 1; i <= 10; i++) {
                    synchronized (bankCard){
                        if (bankCard.getMoney() >= 1000){

                            bankCard.setMoney(bankCard.getMoney()-1000);
                            System.out.println(Thread.currentThread().getName() + "第" + i + "次取了1000元" + "现卡上余额: " + bankCard.getMoney());
                        }else{
                            System.out.println("余额不足...");
                            i--;
                        }
                    }

                }
            }
        };

        //3. 创建两个线程
        Thread boy = new Thread(addMoney, "jack");
        Thread girl = new Thread(subMoney, "rose");

        boy.start();
        girl.start();

    }
}

(2) 同步方式2

优化案例二(2): 使用同步方法
public class Ticket1 implements Runnable{

    private int ticket1 = 100;


    @Override
    public void run() {
        while (true){
            if (!sell()){
                break;
            }
        }

    }

    public synchronized boolean sell(){//锁是this 代表当前对象ticket1, 如果是静态方法, 锁则是类Ticket1.class
        if (ticket1 > 0){
            System.out.println(Thread.currentThread().getName() + "卖的第" + (101-ticket1) + "张票");
            ticket1--;
        }
        return true;
    }
}
public class TestSafeTicket1 {

    public static void main(String[] args) {

        //1. 创建票对象
        Ticket1 ticket1 = new Ticket1();

        Thread w1 = new Thread(ticket1, "窗口1");
        Thread w2 = new Thread(ticket1, "窗口2");
        Thread w3 = new Thread(ticket1, "窗口3");
        Thread w4 = new Thread(ticket1, "窗口4");

        w1.start();
        w2.start();
        w3.start();
        w4.start();


    }
}

(3) 同步规则

(4) 经典问题: 死锁

public class MyLock {

    //两个锁: 代表两根筷子,同时拿到这两根筷子才能吃饭
    public static Object lock1 = new Object();
    public static Object lock2 = new Object();

}
public class Boy extends Thread{

    @Override
    public void run() {
        synchronized (MyLock.lock1){
            System.out.println("男孩拿到了筷子A");
            synchronized (MyLock.lock2){
                System.out.println("男孩拿到了筷子B");
                System.out.println("男孩可以吃饭了");
            }
        }
    }
}
public class Girl extends Thread{

    @Override
    public void run() {
        synchronized (MyLock.lock2){
            System.out.println("女孩拿到了筷子B");
            synchronized (MyLock.lock1){
                System.out.println("女孩拿到了筷子A");
                System.out.println("女孩可以吃饭了");
            }
        }
    }
}
public class TestDeadLock {

    public static void main(String[] args) {

        //1. 创建两个线程对象男孩, 女孩
        Boy boy = new Boy();
        Girl girl = new Girl();

        //2. 女孩线程启动
        girl.start();
        //3. 休息0.5秒钟(如果他们两个同时启动就会造成死锁)
        try {
            Thread.sleep(500);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        //4. 最后启动男孩线程
        boy.start();


    }
}

(5) 线程通信

银行卡类

public class BankCard {

    //余额
    private double money;
    //标记
    private boolean flag = false;//true 表示有钱可以取不能存, false表示没钱可以存不能取

    //存钱
    public synchronized void deposit(double m){//this
        while (flag){//有钱
            try {
                this.wait();//进入等待队列 调用wait()方法的对象一定是锁,this代表锁
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        money = money + m;
        System.out.println(Thread.currentThread().getName() + "存了" + m + "元, 当前余额为: " + money);
        //修改标记
        flag = true;
        //唤醒取钱线程
        this.notifyAll();
    }
    //取钱
    public synchronized void draw(double m){//this
        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 Deposit implements Runnable{

    private BankCard bankCard;
    public Deposit(BankCard bankCard){
        this.bankCard = bankCard;
    }

    @Override
    public void run() {
        for (int i = 1; i <= 10; i++) {
            bankCard.deposit(1000);
        }

    }
}

取钱

public class Draw implements Runnable{

    private BankCard bankCard;

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

    @Override
    public void run() {
        for (int i = 1; i <= 10; i++) {
            bankCard.draw(1000);
        }
    }
}

(6) 经典问题: 生产者, 消费者

若干个生产者在生产产品, 这些产品将提供给若干个消费者去消费, 为了使生产者和消费者能并发执行, 在两者之间设置一个能存储多个产品的缓冲区, 生产者将生产的产品放入缓冲区中, 消费者从缓冲区中取走产品进行消费, 显然生产者和消费者之间必须保持同步, 即不允许消费者到一个空的缓冲区中取产品, 也不允许生产者向一个满的缓冲区中放入产品

面包类

public class Bread {

    private int id;//产品id
    private String productName;//产家名称

    public Bread(int id, String productName) {
        this.id = id;
        this.productName = productName;
    }

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    public String getProductName() {
        return productName;
    }

    public void setProductName(String productName) {
        this.productName = productName;
    }
}

存放面包的容器

public class BreadCon {

    //存放面包的数组
    private Bread[] cons = new Bread[6];
    //存放面包的位置
    private int index = 0;

    //存放面包
    public synchronized void input(Bread b){ // 锁this
        //判断容器有没有满
        while (index >= 6){
            try {
                this.wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        cons[index] = b;
        System.out.println(Thread.currentThread().getName() + "生产了" + b.getId() + "号产品");
        index++;
        //唤醒
        this.notifyAll();

    }

    //取出面包
    public synchronized void output(){ // 锁this
        while (index <= 0){
            try {
                this.wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        index--;
        Bread b = cons[index];
        System.out.println(Thread.currentThread().getName() + "消费了" + b.getProductName() + "生产的" + b.getId() + "号产品");
        cons[index] = null;
        //唤醒
        this.notifyAll();
    }
}

生产类

public class Product implements Runnable{
    private BreadCon con;

    public Product(BreadCon con) {
        this.con = con;
    }

    @Override
    public void run() {
        for (int i = 0; i < 30; i++) {
            con.input(new Bread(i, Thread.currentThread().getName()));
        }
    }
}

消费类

public class Consume implements Runnable{
    private BreadCon con;

    public Consume(BreadCon con) {
        this.con = con;
    }

    @Override
    public void run() {
        for (int i = 0; i < 30; i++) {
            con.output();
        }
    }
}

测试

public class Test {

    public static void main(String[] args) {
        //容器
        BreadCon con = new BreadCon();

        //生产和消费
        Product product = new Product(con);
        Consume consume = new Consume(con);

        //创建线程对象
        Thread p1 = new Thread(product, "1号厂家");
        Thread c1 = new Thread(consume, "1号消费者");
        Thread p2 = new Thread(product, "2号厂家");
        Thread c2 = new Thread(consume, "2号消费者");

        //启动线程
        p1.start();
        c1.start();
        p2.start();
        c2.start();
        
    }
}

10. 线程池

(1) 线程池
(2) 线程池原理
(3) 创建线程池
public class Demo01 {

    public static void main(String[] args) {
        //1. 创建线程池
        //1.1 创建固定线程个数的线程池
        //ExecutorService es = Executors.newFixedThreadPool(4);
        //1.2 创建缓存线程池, 线程个数由任务个数决定
        ExecutorService es = Executors.newCachedThreadPool();
        //1.3 创建单线程池
        //Executors.newSingleThreadExecutor();
        //1.4 创建调度线程池
        //Executors.newScheduledThreadPool(3);
        //2. 创建任务
        Runnable runnable = new Runnable() {
            private int ticket = 100;
            @Override
            public void run() {
                while (true){
                    if (ticket <= 0){
                        break;
                    }
                    System.out.println(Thread.currentThread().getName() + "卖的第" + (101-ticket) + "张票");
                    ticket--;
                }
            }
        };
        //3. 提交任务
        for (int i = 0; i < 4; i++) {
            es.submit(runnable);
        }
        //4. 关闭线程池
        es.shutdown();//等待所有任务执行完毕后才会结束,关闭线程池
        //es.shutdownNow();//试图停止所有正在执行的活动任务, 暂停处理正在等待的任务,并返回等待执行的任务列表

    }
}
(4) Callable接口

public interface Callable{

? public V call() throws Exception;

}

使用Callable实现1-100的和

public class Demo02 {

    public static void main(String[] args) throws Exception{

        //功能需求: 使用Callable实现1-100的和
        //1. 创建Callable对象
        Callable<Integer> callable = new Callable<Integer>() {
            @Override
            public Integer call() throws Exception {
                System.out.println(Thread.currentThread().getName() + "开始计算: ");
                int sum = 0;
                for (int i = 1; i <= 100; i++) {
                    sum += i;
                }
                return sum;
            }
        };
        //2. 把Callable对象转成可执行的任务
        FutureTask<Integer> task = new FutureTask<>(callable);

        //3. 创建线程
        Thread thread = new Thread(task);

        //4. 启动线程
        thread.start();

        //5. 获取结果(等待call方法执行完毕,才会返回)
        Integer sum = task.get();
        System.out.println("结果是: " + sum);

    }
}

使用线程池计算1-100的和

public class Demo03 {

    public static void main(String[] args) throws Exception{
        
        //1. 创建线程池
        ExecutorService es = Executors.newFixedThreadPool(1);
        //2. 提交任务Future:表示将要执行完任务的结果
        Future<Integer> future = es.submit(new Callable<Integer>() {
            @Override
            public Integer call() throws Exception {
                System.out.println(Thread.currentThread().getName() + "开始计算: ");
                int sum = 0;
                for (int i = 1; i <= 100; i++) {
                    sum += i;
                    Thread.sleep(10);
                }
                return sum;
            }
        });
        //3. 获取任务结果,等待任务执行完毕才会返回
        System.out.println(future.get());

        //4. 关闭线程池
        es.shutdown();
    }
}
(5) Future接口
public class Demo04 {

    public static void main(String[] args) throws Exception{

        //1. 创建线程池
        ExecutorService es = Executors.newFixedThreadPool(2);
        //2. 提交任务
        Future<Integer> future1 = es.submit(new Callable<Integer>() {
            @Override
            public Integer call() throws Exception {
                int sum = 0;
                for (int i = 1; i <= 50; i++) {
                    sum += i;
                }
                System.out.println("1~50计算完毕");
                return sum;
            }
        });
        Future<Integer> future2 = es.submit(new Callable<Integer>() {
            @Override
            public Integer call() throws Exception {
                int sum = 0;
                for (int i = 51; i <= 100; i++) {
                    sum += i;
                }
                System.out.println("51~100计算完毕");
                return sum;
            }
        });

        //3. 获取结果
        int sum = future1.get() + future2.get();
        System.out.println("结果是: " + sum);

        //4. 关闭线程池
        es.shutdown();

    }
}
(6) 线程的同步和异步

11. Lock接口

(1) 重入锁
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

public class MyList {

    private Lock lock = new ReentrantLock();
    private String[] str = {"A", "B", "", "", ""};
    private int count = 2;

    public void add(String value){
        lock.lock();
        try{
            str[count] = value;
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            count++;
        } finally {
            lock.unlock();
        }
    }

    public String[] getStr(){
        return str;
    }
}
public class TestMyList {

    public static void main(String[] args) throws Exception{

        MyList list = new MyList();
        Runnable runnable1 = new Runnable() {
            @Override
            public void run() {
                list.add("hello");
            }
        };
        Runnable runnable2 = new Runnable() {
            @Override
            public void run() {
                list.add("world");
            }
        };

        Thread t1 = new Thread(runnable1);
        Thread t2 = new Thread(runnable2);

        t1.start();
        t2.start();

        t1.join();
        t2.join();

        System.out.println(Arrays.toString(list.getStr()));
    }
}

使用重入锁实现4个窗口共同卖100张票

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

public class Ticket implements Runnable{

    private int ticket = 100;
    private Lock lock = new ReentrantLock();

    @Override
    public void run() {

        while (true){
            lock.lock();
            try {

                if (ticket <= 0){
                    break;
                }
                System.out.println(Thread.currentThread().getName() + "卖的第" + (101-ticket) + "张票");
                ticket--;

            } finally {
                lock.unlock();
            }
        }
    }
}
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class TestTicket {

    public static void main(String[] args) {

        //1. 创建票对象
        Ticket ticket = new Ticket();

        //2. 创建线程池对象
        ExecutorService es = Executors.newFixedThreadPool(4);

        //3. 提交任务
        for (int i = 0; i < 4; i++) {
            es.submit(ticket);
        }
		//4. 关闭线程池
        es.shutdown();



    }
}
(2) 读写锁
import java.util.concurrent.locks.ReentrantReadWriteLock;
import java.util.concurrent.locks.ReentrantReadWriteLock.ReadLock;
import java.util.concurrent.locks.ReentrantReadWriteLock.WriteLock;

public class ReadWriteLock {

    //创建读写锁
    private 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(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("读取: " + this.value);
            return this.value;
        } finally {
            readLock.unlock();
        }
    }

    //写入
    public void setValue(String value){
        //使用写锁上锁
        writeLock.lock();

        try {
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            this.value = value;
            System.out.println("写入: " + value);
        } finally {
            writeLock.unlock();
        }
    }

}

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

public class TestReadWriteLock {

    public static void main(String[] args) {
        //1. 创建读写锁对象
        ReadWriteLock rwl = new ReadWriteLock();
        //2. 创建线程池
        ExecutorService es = Executors.newFixedThreadPool(20);
        //3. 创建写任务
        Runnable write = new Runnable() {
            @Override
            public void run() {
                rwl.setValue("张三: " + new Random().nextInt(100));
            }
        };
        //4. 创建读任务
        Runnable read = new Runnable() {
            @Override
            public void run() {
                rwl.getValue();
            }
        };
        Long start = System.currentTimeMillis();//获取系统此刻时间(开始)
        //5. 分配2个线程来 写任务
        for (int i = 0; i < 2; i++) {
            es.submit(write);
        }
        //6. 分配18个线程来 读任务
        for (int i = 0; i < 18; i++) {
            es.submit(read);
        }
        //7. 关闭
        es.shutdown();
        while (!es.isTerminated()) {//空转

        }
        Long end = System.currentTimeMillis();//获取系统此刻时间(结束)
        System.out.println("用时: " + (end - start));//3007  如果使用用互斥锁时间为: 20048
    }
}

12. 线程安全的集合

(1)CopyOnWriteArrayList
public class Demo02 {

    public static void main(String[] args) {

        //1. 创建集合
        CopyOnWriteArrayList<String> list = new CopyOnWriteArrayList<>();
        //2. 使用多线程操作
        ExecutorService es = Executors.newFixedThreadPool(5);
        //3. 提交任务
        for (int i = 0; i < 5; i++) {
            es.submit(new Runnable() {
                @Override
                public void run() {
                    for (int j = 0; j < 10; j++) {
                        list.add(Thread.currentThread().getName() + "---" + new Random().nextInt(1000));
                    }
                }
            });
        }
        //4. 关闭线程池
        es.shutdown();
        while (!es.isTerminated()){}
        //5. 打印结果
        System.out.println("元素个数: " + list.size());
        for (String s : list) {
            System.out.println(s);
        }

    }
}
(2)CopyOnWriteArraySet
(3)Queue接口(队列)
public class Demo04 {

    public static void main(String[] args) {

        //1. 创建队列
        Queue<String> queue = new LinkedList<>();// LinkedList是线程不安全的集合,不能使用多线程
        //2. 入队
        queue.offer("香蕉");
        queue.offer("苹果");
        queue.offer("橘子");
        queue.offer("橙子");
        System.out.println("入队完毕, 元素个数: " + queue.size());
        System.out.println(queue.peek());//获取队列第一个元素但不移除
        System.out.println("----------------------");
        //3. 出队
        int size = queue.size();
        for (int i = 0; i < size; i++) {
            System.out.println(queue.poll());//获得第一个元素并移除
        }
        System.out.println("出队完毕, 元素个数: " + queue.size());
    }
}

(4)ConcurrentLinkedQueue
public class Demo05 {

    public static void main(String[] args) throws Exception{
        //1. 创建线程安全集合
        ConcurrentLinkedQueue<Integer> queue = new ConcurrentLinkedQueue<>();
        //2. 入队操作
        Thread thread1 = new Thread(new Runnable() {
            @Override
            public void run() {
                for (int i = 0; i < 5; i++) {
                    queue.offer(i);
                }
            }
        });
        Thread thread2 = new Thread(new Runnable() {
            @Override
            public void run() {
                for (int i = 5; i < 10; i++) {
                    queue.offer(i);
                }
            }
        });
        //3. 启动线程
        thread1.start();
        thread2.start();

        thread1.join();
        thread2.join();
        //4. 出队操作
        int size = queue.size();
        for (int i = 0; i < size; i++) {
            System.out.println(queue.poll());
        }
        System.out.println("出队成功, 元素个数: " + queue.size());

    }
}
(5)BlockingQueue接口
(6)ArrayBlockingQueue
public class Demo06 {

    public static void main(String[] args) throws Exception{

        //1. 创建一个有界队列, 添加数据
        ArrayBlockingQueue<String> queue = new ArrayBlockingQueue<>(5);
        //2. 添加元素
        queue.put("aaa");
        queue.put("bbb");
        queue.put("ccc");
        queue.put("ddd");
        queue.put("eee");
        System.out.println("已经添加了5个元素");
        //queue.put("fff");//无法添加,因为队列此时满了
        //System.out.println("已经添加了6个元素");
        //3. 删除元素
        queue.take();//删除第一个
        System.out.println(queue.toString());


    }
}

使用阻塞队列实现生产者和消费者

public class Demo07 {

    public static void main(String[] args) {

        //1. 创建队列
        ArrayBlockingQueue<Integer> queue = new ArrayBlockingQueue<>(6);
        //2. 创建两个线程
        Thread t1 = new Thread(new Runnable() {
            @Override
            public void run() {
                for (int i = 0; i < 30; i++) {
                    try {
                        queue.put(i);
                        System.out.println(Thread.currentThread().getName() + "生产了第" + i + "个面包");
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }
        }, "张三");
        Thread t2 = new Thread(new Runnable() {
            @Override
            public void run() {
                for (int i = 0; i < 30; i++) {
                    try {
                        queue.take();
                        System.out.println(Thread.currentThread().getName() + "消费了第" + i + "个面包");
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }


                }
            }
        }, "李四");
        //3. 启动线程
        t1.start();
        t2.start();
    }
}
(7)LinkedBlockingQueue

链表结构实现, 有界队列. (默认上限Integer.MAX_VALUE)

(8)ConcurrentHashMap
public class Demo08 {

    public static void main(String[] args) {

        //1. 创建集合
        ConcurrentHashMap<String, String> hashMap = new ConcurrentHashMap<>();
        //2. 使用多线程添加数据
        for (int i = 0; i < 5; i++) {
            new Thread(new Runnable() {
                @Override
                public void run() {
                    for (int j = 0; j < 10; j++) {
                        hashMap.put(Thread.currentThread().getName()+ "---" + j, j + "");
                        System.out.println(hashMap);
                    }
                }
            }).start();
        }
    }
}

原文:https://www.cnblogs.com/MRASdoubleZ/p/14503013.html

评论(0
© 2014 bubuko.com 版权所有 - 联系我们:wmxa8@hotmail.com
打开技术之扣,分享程序人生!