Java教程

Java多线程详解

本文主要是介绍Java多线程详解,对大家解决编程问题具有一定的参考价值,需要的程序猿们随着小编来一起学习吧!

Java多线程详解

    • 进程和线程
    • 实现Runnable接口
    • 初识并发问题
    • 龟兔赛跑例子
    • 实现Callable接口
    • 静态代理模式
    • 线程状态
    • 线程的停止
    • 线程休眠
    • 线程礼让
    • 线程强制执行
    • 观测线程状态
    • 线程的优先级
    • 守护线程
    • 线程同步机制
    • 线程不安全案例
    • synchronized同步方法
    • synchronized同步块
    • CopyOnWriteArrayList集合
    • 死锁
    • Lock锁
    • 生产者和消费者问题
    • 管程法
    • 信号灯法:
    • 线程池
    • 总结

进程和线程

在这里插入图片描述
示例代码:

package com.gavin.demo01;

public class TestThread extends Thread{

    @Override
    public void run() {
        //run方体线程
        for (int i = 0; i < 20; i++) {
            System.out.println("我在看代码---" + i);
        }
    }

    public static void main(String[] args) {
        //main方法是一个主线程
        //创建一个线程对象
        TestThread testThread = new TestThread();
        //调用start方法开启线程
        testThread.start();
        for (int i = 0; i < 1000 ; i++) {
            System.out.println("我在学习多线程---" + i);
        }
    }
}

执行结果:
在这里插入图片描述
可以看出run方法和main方法是同时执行的,都由CPU调度,会出现线程抢夺的问题
使用多线程下载图片示例代码:

package com.gavin.demo01;

import org.apache.commons.io.FileUtils;
import java.io.File;
import java.io.IOException;
import java.net.URL;

public class TestThread2 extends Thread{

    private String url;

    private String name;

    public TestThread2(String url, String name) {
        this.url = url;
        this.name = name;
    }

    @Override
    public void run() {
        WebDownLoad webDownLoad = new WebDownLoad();
        webDownLoad.down(url, name);
        System.out.println("下载文件为:" + name);
    }

    public static void main(String[] args) {
        TestThread2 testThread = new TestThread2("https://www.www.zyiz.net/i/ll/?i=ff1034bf4ec944ed9b9fefb5d9bbeb2c.png?,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBAR2F2aW5DaGVuXw==,size_20,color_FFFFFF,t_70,g_se,x_16#pic_center", "1.jpg");
        TestThread2 testThread2 = new TestThread2("https://www.www.zyiz.net/i/ll/?i=98a80c1487354509baa94b1522e22fe6.png?,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBAR2F2aW5DaGVuXw==,size_20,color_FFFFFF,t_70,g_se,x_16#pic_center", "2.jpg");
        TestThread2 testThread3 = new TestThread2("https://www.www.zyiz.net/i/ll/?i=30244b9ad1eb40d6a2c6f757e458d343.png?,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBAR2F2aW5DaGVuXw==,size_20,color_FFFFFF,t_70,g_se,x_16#pic_center", "3.jpg");
        testThread.start();
        testThread2.start();
        testThread3.start();
    }
}

class WebDownLoad{

    public void down(String url, String name) {
        try {
            FileUtils.copyURLToFile(new URL(url), new File(name));
        } catch (IOException e) {
            e.printStackTrace();
            System.out.println("IO异常,down方法出错");
        }
    }
}

执行结果:
在这里插入图片描述
可以看出,程序启动后三个线程是同时执行的,并不是按照从上往下的顺序执行的,所以才出现图中所示的打印顺序。

实现Runnable接口

在这里插入图片描述
示例代码:

package com.gavin.demo01;

public class TestRunnable implements Runnable{
    @Override
    public void run() {
        //run方法线程
        for (int i = 0; i < 20; i++) {
            System.out.println("我在看代码---" + i);
        }
    }

    public static void main(String[] args) {
        //main方法是一个主线程
        //创建一个线程对象
        TestRunnable testRunnable = new TestRunnable();
        //传入实现Runnable接口的类
        Thread thread = new Thread(testRunnable);
        //调用start方法开启线程
        thread.start();
        for (int i = 0; i < 1000 ; i++) {
            System.out.println("我在学习多线程---" + i);
        }
    }
}

执行结果:
在这里插入图片描述
使用实现Runnable接口来下载图片
示例代码:

package com.gavin.demo01;

import org.apache.commons.io.FileUtils;
import java.io.File;
import java.io.IOException;
import java.net.URL;

public class TestRunnable2 implements Runnable{
    private String url;

    private String name;

    public TestRunnable2(String url, String name) {
        this.url = url;
        this.name = name;
    }

    @Override
    public void run() {
        WebDownLoad2 webDownLoad2 = new WebDownLoad2();
        webDownLoad2.down(url, name);
        System.out.println("下载文件为:" + name);
    }
    public static void main(String[] args) {
        TestThread2 testThread = new TestThread2("https://www.www.zyiz.net/i/ll/?i=ff1034bf4ec944ed9b9fefb5d9bbeb2c.png?,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBAR2F2aW5DaGVuXw==,size_20,color_FFFFFF,t_70,g_se,x_16#pic_center", "1.jpg");
        TestThread2 testThread2 = new TestThread2("https://www.www.zyiz.net/i/ll/?i=98a80c1487354509baa94b1522e22fe6.png?,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBAR2F2aW5DaGVuXw==,size_20,color_FFFFFF,t_70,g_se,x_16#pic_center", "2.jpg");
        TestThread2 testThread3 = new TestThread2("https://www.www.zyiz.net/i/ll/?i=30244b9ad1eb40d6a2c6f757e458d343.png?,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBAR2F2aW5DaGVuXw==,size_20,color_FFFFFF,t_70,g_se,x_16#pic_center", "3.jpg");
        Thread thread = new Thread(testThread);
        Thread thread2 = new Thread(testThread2);
        Thread thread3 = new Thread(testThread3);
        thread.start();
        thread2.start();
        thread3.start();
    }
}

class WebDownLoad2{

    public void down(String url, String name) {
        try {
            FileUtils.copyURLToFile(new URL(url), new File(name));
        } catch (IOException e) {
            e.printStackTrace();
            System.out.println("IO异常,down方法出错");
        }
    }
}

执行结果:
在这里插入图片描述

初识并发问题

多线程操作同一个对象的示例代码:

package com.gavin.Demo02;

//多线程同时操作一个对象
//买火车票的例子
public class TestRunnable3 implements Runnable{

    //票数
    private int ticketNumber = 10;

    @Override
    public void run() {
        while (true) {
            if (ticketNumber <= 0) {
                break;
            }
            try {
                Thread.sleep(200);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println(Thread.currentThread().getName() + "-->拿到了第" + ticketNumber-- + "张票");
        }
    }

    public static void main(String[] args) {
        TestRunnable3 testRunnable = new TestRunnable3();
        Thread thread = new Thread(testRunnable, "小明");
        thread.start();
        Thread thread2 = new Thread(testRunnable, "老师");
        thread2.start();
        Thread thread3 = new Thread(testRunnable, "黄牛党");
        thread3.start();
    }

}

执行结果:
在这里插入图片描述
可以看出小明和黄牛党同时抢到了第9张票,小明和老师同时抢到了第5张票,出现了很大的问题,这个需要以后并发的知识解决。

龟兔赛跑例子

示例代码:

package com.gavin.Demo02;

//模拟龟兔赛跑的例子
public class Race implements Runnable{

    private static String winner;

    @Override
    public void run() {
        for (int i = 1; i <= 100; i++) {
            //让兔子休息5毫秒
            if (Thread.currentThread().getName().equals("兔子") && i % 10 == 0) {
                try {
                    Thread.sleep(5);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
            System.out.println(Thread.currentThread().getName() + "-->跑了" + i + "步");
            Boolean flag = gameOver(i);
            if (flag) {
                break;
            }
        }
    }

    public Boolean gameOver(int steps) {
        if (winner != null) {
            return true;
        } else {
            if (steps >= 100) {
                winner = Thread.currentThread().getName();
                System.out.println("胜利者是:" + winner);
                return true;
            }
        }
        return false;
    }

    public static void main(String[] args) {
        Race race = new Race();
        Thread thread = new Thread(race, "乌龟");
        Thread thread2 = new Thread(race, " 兔子");
        thread.start();
        thread2.start();
    }
}

执行结果:
在这里插入图片描述
用一段代码还原了经典的龟兔赛跑故事,属实不错!

实现Callable接口

在这里插入图片描述
示例代码:

package com.gavin.Demo02;

import org.apache.commons.io.FileUtils;
import java.io.File;
import java.io.IOException;
import java.net.URL;
import java.util.concurrent.*;

//实现Callable接口,用来下载图片
public class TestCallable implements Callable<Boolean> {

    private String url;

    private String name;

    public TestCallable(String url, String name) {
        this.url = url;
        this.name = name;
    }

    @Override
    public Boolean call() throws Exception {
        WebDownLoad2 webDownLoad = new WebDownLoad2();
        webDownLoad.down(url, name);
        System.out.println("下载文件为:" + name);
        return true;
    }

    public static void main(String[] args) throws ExecutionException, InterruptedException {
        TestCallable testCallable = new TestCallable("https://www.www.zyiz.net/i/ll/?i=ff1034bf4ec944ed9b9fefb5d9bbeb2c.png?,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBAR2F2aW5DaGVuXw==,size_20,color_FFFFFF,t_70,g_se,x_16#pic_center", "1.jpg");
        TestCallable testCallable2 = new TestCallable("https://www.www.zyiz.net/i/ll/?i=98a80c1487354509baa94b1522e22fe6.png?,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBAR2F2aW5DaGVuXw==,size_20,color_FFFFFF,t_70,g_se,x_16#pic_center", "2.jpg");
        TestCallable testCallable3 = new TestCallable("https://www.www.zyiz.net/i/ll/?i=30244b9ad1eb40d6a2c6f757e458d343.png?,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBAR2F2aW5DaGVuXw==,size_20,color_FFFFFF,t_70,g_se,x_16#pic_center", "3.jpg");
        //创建执行服务
        ExecutorService executorService = Executors.newFixedThreadPool(3);
        //提交执行
        Future<Boolean> r1 = executorService.submit(testCallable);
        Future<Boolean> r2 = executorService.submit(testCallable2);
        Future<Boolean> r3 = executorService.submit(testCallable3);
        //获取结果
        boolean rs1 = r1.get();
        boolean rs2 = r1.get();
        boolean rs3 = r1.get();
        System.out.println(rs1);
        System.out.println(rs2);
        System.out.println(rs3);
        //关闭服务
        executorService.shutdown();
    }
}
class WebDownLoad2{

    public void down(String url, String name) {
        try {
            FileUtils.copyURLToFile(new URL(url), new File(name));
        } catch (IOException e) {
            e.printStackTrace();
            System.out.println("IO异常,down方法出错");
        }
    }
}

执行结果:
在这里插入图片描述

静态代理模式

示例代码:

package com.gavin.Demo03;

public class StaticProxy {

    public static void main(String[] args) {
        WeddingCompany weddingCompany = new WeddingCompany(new You());
        weddingCompany.HappyMarry();
    }

}

interface Marry {

    void HappyMarry();
}

class You implements Marry {

    @Override
    public void HappyMarry() {
        System.out.println("今天要Happy哦!!!");
    }
}

class WeddingCompany implements Marry {

    private Marry target;

    public WeddingCompany(Marry target) {
        this.target = target;
    }

    @Override
    public void HappyMarry() {
        before();
        this.target.HappyMarry();
        after();
    }

    public void before() {
        System.out.println("昨天Happy!!!");
    }

    public void after() {
        System.out.println("明天Happy!!!");
    }
}

执行结果:
在这里插入图片描述
可以看出WeddingCompany作为You类的静态代理,不仅可以调用本身的方法,也可以调用代理对象的方法,这就是静态代理的思想。

线程状态

在这里插入图片描述

线程的停止

使用自己定义的方法用来停止线程
在这里插入图片描述

示例代码:

package com.gavin.Demo04;

public class TestStop implements Runnable{

    //设置一个标识用来停止线程
    private boolean flag = true;

    @Override
    public void run() {
        int i = 0;
        while (flag) {
            System.out.println("执行了-->" + i++ + "次");
        }
    }

    //设一个公开的方法停止线程,转换标志位
    public void stop() {
        this.flag = false;
    }

    public static void main(String[] args) {
        TestStop testStop = new TestStop();
        Thread thread = new Thread(testStop);
        thread.start();
        for (int i = 0; i <= 100 ; i++) {
            System.out.println("main执行了-->" + i + "次");
            if (i == 90) {
                //调用自己的stop方法停止线程
                testStop.stop();
                System.out.println("线程已经停止了");
            }
        }

    }
}

执行结果:
在这里插入图片描述
可以看出当主线程执行到第90次时,调用自定义的线程停止方法,停止了自定义的线程,此时自定义的线程只执行了63次。

线程休眠

在这里插入图片描述
使用Thread.sleep方法完成倒计时功能
示例代码:

package com.gavin.Demo04;

public class TestSleep {

    public static void main(String[] args) {
        try {
            tenDown();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    //使用Thread.sleep方法完成倒计时功能
    public static void tenDown() throws InterruptedException {
        int num = 10;
        while (true) {
            Thread.sleep(1000);
            System.out.println(num);
            num --;
            if (num == 0) {
                break;
            }
        }
    }
}

执行结果:
在这里插入图片描述
使用Thread.sleep方法打印当前系统时间
示例代码:

package com.gavin.Demo04;

import java.text.SimpleDateFormat;
import java.util.Date;

public class TestSleep2 {

    //使用Thread.sleep方法打印当前系统时间
    public static void main(String[] args) throws InterruptedException {
        Date startTime = new Date(System.currentTimeMillis());
        while (true) {
            Thread.sleep(1000);
            System.out.println(new SimpleDateFormat("HH:mm:ss").format(startTime));
            startTime = new Date(System.currentTimeMillis());
        }
    }
}

执行结果:
在这里插入图片描述

线程礼让

在这里插入图片描述
示例代码:

package com.gavin.Demo04;

public class TestYield {

    public static void main(String[] args) {
        MyYield myYield = new MyYield();
        Thread thread = new Thread(myYield, "a");
        Thread thread2 = new Thread(myYield, "b");
        thread.start();
        thread2.start();
    }
}

class MyYield implements Runnable {

    @Override
    public void run() {
        System.out.println(Thread.currentThread().getName() + "线程开始执行");
        //线程礼让
        Thread.yield();
        System.out.println(Thread.currentThread().getName() + "线程停止执行");
    }
}

执行结果:
在这里插入图片描述
可以看出程序执行时,a线程礼让了b线程

线程强制执行

在这里插入图片描述
示例代码:

package com.gavin.Demo04;

public class TestJoin implements Runnable{

    @Override
    public void run() {
        for (int i = 1; i <= 100; i++) {
            System.out.println("线程VIP来了-->" + i);
        }
    }

    public static void main(String[] args) throws InterruptedException {
        TestJoin testJoin = new TestJoin();
        Thread thread = new Thread(testJoin);
        thread.start();
        //主线程开始执行
        for (int i = 1; i <= 500; i++) {
            if (i == 20) {
                //线程插队
                thread.join();
            }
            System.out.println("main-->" + i);
        }
    }
}

执行结果:
在这里插入图片描述

观测线程状态

在这里插入图片描述
示例代码:

package com.gavin.state;

public class TestState {

    public static void main(String[] args) {
        Thread thread = new Thread(() -> {
            for (int i = 0; i < 5; i++) {
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
            System.out.println("//");
        });

        //观察线程状态
        Thread.State state = thread.getState();
        System.out.println(state);      //NEW

        //观察线程启动后状态
        thread.start();
        state = thread.getState();
        System.out.println(state);      //RUN

        //只要线程不终止,就会一直输出状态
        while (state != Thread.State.TERMINATED) {
            try {
                Thread.sleep(100);
                //更新线程状态
                state = thread.getState();
                //输出状态
                System.out.println(state);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}

执行结果:
在这里插入图片描述

线程的优先级

在这里插入图片描述
示例代码:

package com.gavin.state;

public class TestPriority {

    public static void main(String[] args) {
        System.out.println(Thread.currentThread().getName() + "-->" + Thread.currentThread().getPriority());
        MyPriority myPriority = new MyPriority();
        Thread thread = new Thread(myPriority);
        Thread thread2 = new Thread(myPriority);
        Thread thread3 = new Thread(myPriority);
        Thread thread4 = new Thread(myPriority);
        Thread thread5 = new Thread(myPriority);
        Thread thread6 = new Thread(myPriority);
        //先设置线程的优先级,再启动线程
        thread.start();
        thread2.setPriority(3);
        thread2.start();
        thread3.setPriority(Thread.MAX_PRIORITY);   //Thread.MAX_PRIORITY = 10
        thread3.start();
        thread4.setPriority(Thread.MIN_PRIORITY);   //Thread.MIN_PRIORITY = 1
        thread4.start();
        thread5.setPriority(7);
        thread5.start();
        thread6.setPriority(8);
        thread6.start();
    }
}

class MyPriority implements Runnable{

    @Override
    public void run() {
        System.out.println(Thread.currentThread().getName() + "-->" + Thread.currentThread().getPriority());
    }
}

执行结果:
在这里插入图片描述
可以看出,有时候线程的执行顺序不是按照设定的优先级执行了,这是因为现在的CPU运算速度很块,以及CPU算法的优化,这几个线程几乎在同一时间执行的,所有打印出来的优先级不是自己设置的优先级。

守护线程

在这里插入图片描述
示例代码:

package com.gavin.state;

public class TestDaemon {

    public static void main(String[] args) {
        God god = new God();
        You you = new You();
        Thread thread = new Thread(god);
        //默认是false表示是用户线程,正常的线程都是用户线程
        thread.setDaemon(true);
        //上帝手护线程开启
        thread.start();
        Thread thread2 = new Thread(you);
        //自己的用户线程
        thread2.start();
    }
}

class God implements Runnable {

    @Override
    public void run() {
        while (true) {
            System.out.println("上帝保佑者你");
        }
    }
}

class You implements Runnable {

    @Override
    public void run() {
        for (int i = 0; i < 36500; i++) {
            System.out.println("每一天都活得很开心哦!");
        }
        System.out.println("永别了世界!GoodBy~~~");
    }
}

执行结果:
在这里插入图片描述

线程同步机制

并发的解释:
在这里插入图片描述
线程锁的解释:
在这里插入图片描述

线程不安全案例

银行取钱案例
示例代码:

package com.gavin.syn;

public class UnsafeBank {

    public static void main(String[] args) {
        Account account = new Account("结婚基金", 100);
        Drawing drawing = new Drawing(account, 50, "你");
        Drawing drawing2 = new Drawing(account, 100, "你媳妇");
        drawing.start();
        drawing2.start();
    }
}

class Account {
    String name;

    int balance;

    public Account(String name, int balance) {
        this.name = name;
        this.balance = balance;
    }
}

class Drawing extends Thread {

    Account account;
    //取了多少钱
    int drawingMoney;
    //现在手里还有多少钱
    int nowMoney;

    public Drawing(Account account, int drawingMoney, String name) {
        super(name);
        this.account = account;
        this.drawingMoney = drawingMoney;
    }

    @Override
    public void run() {
        if (account.balance - drawingMoney < 0) {
            System.out.println(Thread.currentThread().getName() + "钱不够,取不了");
            return;
        }
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        //卡内余额
        account.balance =  account.balance - drawingMoney;
        //你手里的钱
        nowMoney = nowMoney + drawingMoney;
        System.out.println(account.name + "余额为:" + account.balance);
        System.out.println(this.getName() + "手里的钱:" + nowMoney);
    }
}

执行结果:
在这里插入图片描述

可以看出,两个线程同时去取钱,余额成了负数,出现了重大的问题。

synchronized同步方法

在这里插入图片描述
使用synchronized优化抢票代码:

package com.gavin.Demo02;

//多线程同时操作一个对象
//买火车票的例子
public class TestRunnable3 implements Runnable{

    //票数
    private int ticketNumber = 10;

    @Override
    public synchronized void run() {
        while (true) {
            if (ticketNumber <= 0) {
                break;
            }
            try {
                Thread.sleep(200);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println(Thread.currentThread().getName() + "-->拿到了第" + ticketNumber-- + "张票");
        }
    }

    public static void main(String[] args) {
        TestRunnable3 testRunnable = new TestRunnable3();
        Thread thread = new Thread(testRunnable, "小明");
        thread.start();
        Thread thread2 = new Thread(testRunnable, "老师");
        thread2.start();
        Thread thread3 = new Thread(testRunnable, "黄牛党");
        thread3.start();
    }

}

执行结果:
在这里插入图片描述

synchronized同步块

在这里插入图片描述
使用synchronized同步块优化银行取钱代码:

package com.gavin.syn;

public class UnsafeBank {

    public static void main(String[] args) {
        Account account = new Account("结婚基金", 100);
        Drawing drawing = new Drawing(account, 50, "你");
        Drawing drawing2 = new Drawing(account, 100, "你媳妇");
        drawing.start();
        drawing2.start();
    }
}

class Account {
    String name;

    int balance;

    public Account(String name, int balance) {
        this.name = name;
        this.balance = balance;
    }
}

class Drawing extends Thread {

    Account account;
    //取了多少钱
    int drawingMoney;
    //现在手里还有多少钱
    int nowMoney;

    public Drawing(Account account, int drawingMoney, String name) {
        super(name);
        this.account = account;
        this.drawingMoney = drawingMoney;
    }

    @Override
    public void run() {
        synchronized (account) {
            if (account.balance - drawingMoney < 0) {
                System.out.println(Thread.currentThread().getName() + "钱不够,取不了");
                return;
            }
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            //卡内余额
            account.balance =  account.balance - drawingMoney;
            //你手里的钱
            nowMoney = nowMoney + drawingMoney;
            System.out.println(account.name + "余额为:" + account.balance);
            System.out.println(this.getName() + "手里的钱:" + nowMoney);
        }
    }
}

执行结果:
在这里插入图片描述

CopyOnWriteArrayList集合

CopyOnWriteArrayList集合是线程安全的,具体请看下面的示例代码:

package com.gavin.syn;

import java.util.concurrent.CopyOnWriteArrayList;

public class TestJUC {

    public static void main(String[] args) {
        CopyOnWriteArrayList<String> arrayList = new CopyOnWriteArrayList<>();
        for (int i = 0; i < 10000; i++) {
            new Thread(() -> {
                arrayList.add(Thread.currentThread().getName());
            }).start();
        }
        try {
            Thread.sleep(3000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("CopyOnWriteArrayList集合长度为:" + arrayList.size());
    }
}

执行结果:
在这里插入图片描述

死锁

在这里插入图片描述
示例代码:

package com.gavin.thread;

public class DeadLock {

    public static void main(String[] args) {
        Makeup makeup = new Makeup(0, "小兰");
        Makeup makeup2 = new Makeup(1, "小美");
        makeup.start();
        makeup2.start();
    }
}

//口红类
class Lipstick {

}
//镜子类
class Mirror {

}
class Makeup extends Thread {
    static Lipstick lipstick = new Lipstick();
    static Mirror mirror = new Mirror();

    int choice;
    String girlName;

    Makeup(int choice, String girlName) {
        this.choice = choice;
        this.girlName = girlName;
    }

    @Override
    public void run() {
        try {
            makeup();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    public void makeup() throws InterruptedException {
        if (choice == 0) {
            synchronized (lipstick) {
                System.out.println(this.girlName + "拿到口红");
                Thread.sleep(1000);
                synchronized (mirror) {
                    System.out.println(this.girlName + "拿到镜子");
                }
            }
        } else {
            synchronized (mirror) {
                System.out.println(this.girlName + "拿到镜子");
                Thread.sleep(2000);
                synchronized (lipstick) {
                    System.out.println(this.girlName + "拿到口红");
                }
            }
        }
    }
}

执行结果:
在这里插入图片描述
可以看出程序进入了死锁状态

产生死锁的四个必要条件:
在这里插入图片描述

Lock锁

在这里插入图片描述
示例代码:

package com.gavin.thread;

import java.util.concurrent.locks.ReentrantLock;

public class TestLock {

    public static void main(String[] args) {
        TestLock2 testLock2 = new TestLock2();
        Thread thread = new Thread(testLock2);
        Thread thread2 = new Thread(testLock2);
        Thread thread3 = new Thread(testLock2);
        thread.start();
        thread2.start();
        thread3.start();
    }
}

class TestLock2 implements Runnable {

    int tickNumber = 10;

    //定义lock锁
    private final ReentrantLock reentrantLock = new ReentrantLock();

    @Override
    public void run() {
        while (true) {
            try {
                //加锁
                reentrantLock.lock();
                if (tickNumber > 0) {
                    System.out.println("剩余票数:" + tickNumber --);
                } else {
                    break;
                }
            } catch (Exception e) {
                e.printStackTrace();
            } finally {
                //线程执行完解锁
                reentrantLock.unlock();
            }
        }
    }
}

执行结果:
在这里插入图片描述
synchronized和Lock锁的区别:
在这里插入图片描述

生产者和消费者问题

在这里插入图片描述
在这里插入图片描述
应用场景:
在这里插入图片描述

管程法

在这里插入图片描述
示例代码:

package com.gavin.thread;


public class TestPC {

    public static void main(String[] args) {
        SynContainer synContainer = new SynContainer();
        Product product = new Product(synContainer);
        Customer customer = new Customer(synContainer);
        product.start();
        customer.start();
    }
}

class Product extends Thread {

    SynContainer synContainer;

    Product(SynContainer synContainer) {
        this.synContainer = synContainer;
    }

    @Override
    public void run() {
        for (int i = 0; i < 100; i++) {
            synContainer.push(new Chicken(i));
            System.out.println("生产了" + i + "只鸡");
        }
    }
}

class Customer extends Thread {

    SynContainer synContainer;

    Customer(SynContainer synContainer) {
        this.synContainer = synContainer;
    }

    @Override
    public void run() {
        for (int i = 0; i < 100; i++) {
            System.out.println("消费了" + synContainer.pop().id + "只鸡");
        }
    }
}

class Chicken {

    int id;

    Chicken(int id) {
        this.id = id;
    }
}

class SynContainer {

    Chicken[] chickens = new Chicken[10];

    int count = 0;

    public synchronized void push(Chicken chicken) {
        //如果容器满了,就等待消费者消费
        if (count == chickens.length) {
            try {
                this.wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        chickens[count] = chicken;
        count++;
        //可以通知消费者消费了
        this.notifyAll();
    }

    public synchronized Chicken pop() {
        //没有就等待生产者生产
        if (count == 0) {
            try {
                this.wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        //有就消费
        count--;
        Chicken chicken = chickens[count];
        //通知生产者生产
        this.notifyAll();
        return chicken;
    }
}

执行结果:
在这里插入图片描述

信号灯法:

在这里插入图片描述
示例代码:

package com.gavin.thread;

public class TestPC2 {

    public static void main(String[] args) {
        TV tv = new TV();
        Player player = new Player(tv);
        Watcher watcher = new Watcher(tv);
        player.start();
        watcher.start();
    }
}

class Player extends Thread{

    TV tv;

    Player(TV tv) {
        this.tv = tv;
    }

    @Override
    public void run() {
        for (int i = 0; i < 20; i++) {
            if (i % 2 == 0) {
                this.tv.play("B站");
            } else {
                this.tv.play("抖音");
            }
        }
    }
}

class Watcher extends Thread{
    TV tv;

    Watcher(TV tv) {
        this.tv = tv;
    }

    @Override
    public void run() {
        for (int i = 0; i < 20; i++) {
            this.tv.watch();
        }
    }
}

class TV {

    //表演的节目名称
    String voice;

    //演员表演标识
    boolean flag = true;

    public synchronized void play(String voice) {
        if (!flag) {
            try {
                this.wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        System.out.println("演员表演了:" + voice);
        //通知观众观看
        this.notifyAll();
        this.voice = voice;
        this.flag = !this.flag;
    }

    public synchronized void watch() {
        if (flag) {
            try {
                this.wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        System.out.println("观众观看了:" + voice);
        //通知演员表演
        this.notifyAll();
        this.flag = !this.flag;
    }

}

执行结果:
在这里插入图片描述

线程池

在这里插入图片描述

在这里插入图片描述
示例代码:

package com.gavin.thread;

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

public class TestPool {

    public static void main(String[] args) {
        //创建10个线程
        ExecutorService service = Executors.newFixedThreadPool(10);
        //执行线程
        service.execute(new MyThread());
        service.execute(new MyThread());
        service.execute(new MyThread());
        service.execute(new MyThread());
        service.execute(new MyThread());
        //关闭线程
        service.shutdown();
    }

}

class MyThread implements Runnable {

    @Override
    public void run() {
        System.out.println(Thread.currentThread().getName());
    }
}

执行结果:
在这里插入图片描述

总结

三种创建线程的方法
示例代码:

package com.gavin.thread;

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

public class ThreadNew {

    public static void main(String[] args) {
        new MyThread1().start();
        new Thread(new MyThread2()).start();
        FutureTask<Integer> futureTask = new FutureTask<Integer>(new MyThread3());
        new Thread(futureTask).start();
        try {
            Integer number = futureTask.get();
            System.out.println(number);
        } catch (InterruptedException e) {
            e.printStackTrace();
        } catch (ExecutionException e) {
            e.printStackTrace();
        }
    }
}

class MyThread1 extends Thread {

    @Override
    public void run() {
        System.out.println("MyThread1");
    }
}

class MyThread2 implements Runnable {

    @Override
    public void run() {
        System.out.println("MyThread2");
    }
}

class MyThread3 implements Callable<Integer> {

    @Override
    public Integer call() throws Exception {
        System.out.println("MyThread3");
        return 100;
    }
}

执行结果:
在这里插入图片描述

这篇关于Java多线程详解的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!