JAVA多线程学习基础学习

2021/7/19 14:36:00

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

JAVA多线程

    • 多线程概念
      • 进程和线程
      • 多线程业务场景
    • 多线程创建方式
      • 继承Thread类
        • 使用多线程实现多文件下载
    • 实现Runnable接口
    • 实现Callable接口
    • 并发问题
    • 静态代理
    • Lambda表达式
    • 线程状态
    • 线程休眠(Thread.sleep())
    • 线程礼让(Thread.yield())
    • 线程强制执行(join)
    • 线程观测状态(thread.getState())
    • 线程优先级(setPriority())
    • 守护线程(setDaemon(true))
    • 三个不安全例子
    • 线程安全
    • 死锁
    • LOCK锁

多线程概念

简单介绍:多线程是CPU同时处理多个任务
现实场景:人边吃饭边玩手机,属于多线程的范畴

进程和线程

简单介绍:进程包含线程
实际场景:看视频时,视频播放,声音播放,字幕加载

进程由系统分配,线程则是实际的功能执行

代码中模拟的多线程,他是由单核CPU执行只是切换的很块,每个一点点执行,看起来像是同时执行。
真正的多线程是指,多CPU,既多核执行

多线程业务场景

实际场景:当秒杀商品时,就是多个线程在执行,多线程互相争抢资源,就需要给他们排队,来控制资源的抢夺。

多线程创建方式

继承Thread类

注意点:线程启动之后并不会立即执行,将会由CPU调度执行

package Thread;

/**
 * @className: ThreadTest1
 * @description:
 * @createDate: 2021年06月25日 11:11:22
 * @author: ns
 */
public class ThreadTest1 extends Thread {
    public static void main(String[] args) {

        ThreadTest1 threadTest1 = new ThreadTest1();
        threadTest1.start();

        for (int i = 0; i < 2000; i++) {
            System.out.println("看代码" + i);
        }
    }

    public void run() {
        for (int i = 0; i < 10; i++) {
            System.out.println("学习多线程代码" + i);
        }
    }
}

运行效果
在这里插入图片描述

使用多线程实现多文件下载

包下载路径
https://search.maven.org/artifact/org.apache.directory.studio/org.apache.commons.io/2.4/jar

package Thread;

import org.apache.commons.io.FileUtils;

import java.io.File;
import java.io.IOException;
import java.net.URL;

/**
 * @className: ThreadTest2
 * @description:
 * @createDate: 2021年06月25日 14:08:56
 * @author: ns
 */
public class ThreadTest2 extends Thread {

    private String url;

    private String name;

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

    public void run() {
        WebDownLoader webDownLoader = new WebDownLoader();
        webDownLoader.downLoader(url, name);
        System.out.println("下载了文件名为" + name);
    }

    public static void main(String[] args) {
        ThreadTest2 threadTest1 = new ThreadTest2("https://www.www.zyiz.net/i/ll/?i=2021061516385914.png#pic_center", "图1.png");
        ThreadTest2 threadTest2 = new ThreadTest2("https://www.www.zyiz.net/i/ll/?i=20210615175631519.png#pic_center", "图2.png");
        ThreadTest2 threadTest3 = new ThreadTest2("https://www.www.zyiz.net/i/ll/?i=20210616110215957.png#pic_center", "图3.png");
        threadTest1.start();
        threadTest2.start();
        threadTest3.start();
    }
}

class WebDownLoader {

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

实现Runnable接口

package Thread;

/**
 * @className: ThreadTest3
 * @description:
 * @createDate: 2021年06月25日 14:30:08
 * @author: ns
 */
public class ThreadTest3 implements Runnable{

    public static void main(String[] args) {
        ThreadTest3 threadTest1 = new ThreadTest3();
        //代理
        new Thread(threadTest1).start();
        for (int i = 0; i < 2000; i++) {
            System.out.println("看代码" + i);
        }
    }

    public void run() {
        for (int i = 0; i < 10; i++) {
            System.out.println("学习多线程代码" + i);
        }
    }
}

总结:避免单继承的局限性,推荐使用Runnable实现多线程,方便同一个对象被多个线程使用

实现Callable接口

package org.ck.thread.callable;

import org.ck.thread.ThreadTest2;
import org.ck.thread.WebDownLoader;

import java.util.concurrent.*;

/**
 * @className: TestCallAble
 * @description: 实现callable 接口
 * @createDate: 2021年06月25日 17:39:45
 * @author: ns
 */
public class TestCallAble implements Callable<Boolean> {

    private String url;

    private String name;

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

    public static void main(String[] args) {
        TestCallAble threadTest1 = new TestCallAble("https://www.www.zyiz.net/i/ll/?i=2021061516385914.png#pic_center", "图1.png");
        TestCallAble threadTest2 = new TestCallAble("https://www.www.zyiz.net/i/ll/?i=20210615175631519.png#pic_center", "图2.png");
        TestCallAble threadTest3 = new TestCallAble("https://www.www.zyiz.net/i/ll/?i=20210616110215957.png#pic_center", "图3.png");
        ExecutorService ser = Executors.newFixedThreadPool(3);
        Future<Boolean> r1 = ser.submit(threadTest1);
        Future<Boolean> r2 = ser.submit(threadTest2);
        Future<Boolean> r3 = ser.submit(threadTest3);
        try {
            System.out.println(r1.get());
            System.out.println(r2.get());
            System.out.println(r3.get());
        } catch (InterruptedException e) {
            e.printStackTrace();
        } catch (ExecutionException e) {
            e.printStackTrace();
        }
        ser.shutdown();
    }

    @Override
    public Boolean call() {
        WebDownLoader webDownLoader = new WebDownLoader();
        webDownLoader.downLoader(url, name);
        System.out.println("下载了文件名为" + name);
        return true;
    }
}

总结:相比Runnable和Thread实现的线程,callable,使用了线程池,并让线程有了返回结果。

并发问题

模拟抢票

package Thread;

/**
 * @className: ThreadTest4
 * @description:
 * @createDate: 2021年06月25日 14:42:41
 * @author: ns
 */
public class ThreadTest4 implements Runnable {

    private int ticketNums = 10;

    public void run() {
        while (true) {
            if (ticketNums <= 0) {
                break;
            }
            //模拟延时
            try {
                Thread.sleep(200);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println(Thread.currentThread().getName() + "拿到了第" + ticketNums-- + "张");
        }
    }

    public static void main(String[] args) {
        ThreadTest4 ticket = new ThreadTest4();

        new Thread(ticket, "小明").start();
        new Thread(ticket, "老师").start();
        new Thread(ticket, "黄牛党").start();

    }
}

运行结果
在这里插入图片描述
不应该有-1

静态代理

package org.ck.thread.proystatic;

/**
 * @className: StaticProxy
 * @description: 静态代理:代理类似面向切面编程,注解和这个很像,找到横切面
 * 真实对象与代理角色都要实现同一个接口
 * 代理对象可以帮助真实对象做琐事
 * 真实对象只专注自己的事
 * @createDate: 2021年06月28日 11:05:39
 * @author: ns
 */

public class StaticProxy {

    public static void main(String[] args) {
        //线程实现
        new Thread(()-> System.out.println("爱")).start();
        //结婚代理
        new WeddingCompany(new You()).HappyMarry();

  /*      //自己结婚
        You you = new You();
        //代理结婚
        WeddingCompany weddingCompany = new WeddingCompany(new You());
        weddingCompany.HappyMarry();*/
    }
}

interface Marry {
    //久旱逢甘露
    //他乡遇故知
    //金榜题名时
    void HappyMarry();
}

//真实角色,你去结婚
class You implements Marry {

    @Override
    public void HappyMarry() {
        System.out.println("结婚");
    }
}

//代理角色,帮助你结婚
class WeddingCompany implements Marry {

    private Marry target;

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

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

    private void after() {
        System.out.println("收尾款");
    }

    private void before() {
        System.out.println("布置现场");
    }
}

在这里插入图片描述
静态代理总结:代理和代理对象通过实现同一个接口完成静态代理。属于AOP面向切面编程。

Lambda表达式

函数式接口 案例

@FunctionalInterface
public interface Runnable {
    public abstract void run();
}

测试类

package org.ck.thread.lambda;

/**
 * @className: LambdaTest
 * @description:
 * @createDate: 2021年06月28日 11:39:20
 * @author: ck
 */
public class LambdaTest {

    //静态内部类
    static class Like2 implements ILike {
        @Override
        public void lambda() {
            System.out.println("i like lambda2");
        }
    }

    public static void main(String[] args) {
        ILike like = new Like();
        like.lambda();

        like = new Like2();
        like.lambda();

        //4.局部内部类
        class Like3 implements ILike {
            @Override
            public void lambda() {
                System.out.println("i like lambda3");
            }
        }
        like = new Like3();
        like.lambda();

        //5.匿名内部类 没有类的名称,必须借助接口或父类
        like = new ILike() {
            @Override
            public void lambda() {
                System.out.println("i like lambda4");
            }
        };
        like.lambda();
        //6.用lambda简化
        //一个接口只包含一个抽象方法,那么他就是一个函数式接口
        like = () ->{
            System.out.println("i like lambda5");
        };
        like.lambda();
    }
}

//1.定义一个函数式接口
interface ILike {
    void lambda();
}

//2.实现类
class Like implements ILike {
    @Override
    public void lambda() {
        System.out.println("i like lambda");
    }
}

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

测试类2

package org.ck.thread.lambda;

/**
 * @className: LambadLoveTest
 * @description:
 * @createDate: 2021年07月03日 18:18:49
 * @author: ck
 */
public class LambdaLoveTest {
    public static void main(String[] args) {
  /*      Love love = new Love();
        love.love(2);*/
        int b = 20;
        ILove iLove = (a) -> {
            System.out.println("测试" + a);
        };

        iLove = a -> {
            System.out.println("测试" + a);
        };
        //
        iLove = a -> System.out.println("测试" + a);
        iLove.love(b);
    }

}

interface ILove {
    void love(int a);
}

class Love implements ILove {

    @Override
    public void love(int a) {
        System.out.println("love one" + a);
    }
}

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

线程状态

new Thread() 创建状态
start就绪状态
run运行状态
sleep,wait 阻塞
dead run自然结束就是死亡

package org.ck.thread.status;

/**
 * @className: TestStop
 * @description: 测试stop 线程正常停止,不建议死循环
 * 建议使用标志位-->设置一个标志位
 * 不要使用stop或者destroy等过时或JDK不建议的方法
 * @createDate: 2021年07月07日 11:19:45
 * @author: ck
 */
public class TestStop implements Runnable {

    //1.设置标志
    boolean flag = true;

    @Override
    public void run() {
        int i = 0;
        while (flag) {
            System.out.println("run...Thread" + i++);
        }
    }

    //2.设置公开方法停止线程
    public void stop() {
        this.flag = false;
    }

    public static void main(String[] args) {
        TestStop testStop = new TestStop();
        new Thread(testStop).start();
        for (int i = 0; i < 1000; i++) {
            System.out.println("main" + i);
            if (i== 900) {
                testStop.stop();
                System.out.println("线程该停止了");
            }
        }
    }
}

运行结果
在这里插入图片描述
PS:run中的i与main方法中的i不同,所以不用管run的I走到了哪里

线程休眠(Thread.sleep())

黄牛抢票模拟

package org.ck.thread.status;
/**
 * @className: TestSleep
 * @description: 模拟网络延时
 * @createDate: 2021年07月07日 11:33:05
 * @author: ck
 */
public class TestSleep implements Runnable{

    private int ticketNums = 10;

    public void run() {
        while (true) {
            if (ticketNums <= 0) {
                break;
            }
            //模拟延时
            try {
                Thread.sleep( 100);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println(Thread.currentThread().getName() + "拿到了第" + ticketNums-- + "张");
        }
    }

    public static void main(String[] args) {
        TestSleep ticket = new TestSleep();
        new Thread(ticket, "小明").start();
        new Thread(ticket, "老师").start();
        new Thread(ticket, "黄牛党").start();

    }
}

运行结果
在这里插入图片描述
sleep自带锁
倒计时模拟

package org.ck.thread.status;

/**
 * @className: TestSleep
 * @description: 模拟网络延时
 * @createDate: 2021年07月07日 11:33:05
 * @author: ck
 */
public class TestSleep implements Runnable{

    private int ticketNums = 10;

    public void run() {
        while (true) {
            if (ticketNums <= 0) {
                break;
            }
            //模拟延时
            try {
                Thread.sleep( 100);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println(Thread.currentThread().getName() + "拿到了第" + ticketNums-- + "张");
        }
    }

    public static void main(String[] args) {
        TestSleep ticket = new TestSleep();
        new Thread(ticket, "小明").start();
        new Thread(ticket, "老师").start();
        new Thread(ticket, "黄牛党").start();

    }
}

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

线程礼让(Thread.yield())

package org.ck.thread.status;

/**
 * @className: TestYield
 * @description: 线程礼让不一定成功
 * @createDate: 2021年07月07日 15:08:59
 * @author: ck
 */
public class TestYield {

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

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

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

线程强制执行(join)

package org.ck.thread.status;

/**
 * @className: TestJoin
 * @description: 测试join方法
 * @createDate: 2021年07月07日 15:26:59
 * @author: ck
 */
public class TestJoin implements Runnable {
    @Override
    public void run() {
        for (int i = 0; i < 1000; 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 = 0; i < 500; i++) {
            if (i == 10) {
                thread.join();//插队
            }
            System.out.println("main" + i);
        }


    }
}

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

线程观测状态(thread.getState())

NEW 创建状态
RUNNABLE
运行状态
BLOCKED
阻塞状态
WAITING
等待状态
TIMED_WAITING
等待零一个线程达到指定时间
TERMINATED
退出的线程

package org.ck.thread.status;

/**
 * @className: TestState
 * @description:
 * @createDate: 2021年07月07日 15:54:22
 * @author: ck
 */
public class TestState {

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

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

        //观察启动后
        thread.start();//启动
        state = thread.getState();
        System.out.println(state);//run

        while (state != Thread.State.TERMINATED) {
            Thread.sleep(100);
            state = thread.getState();
            System.out.println(state);
        }
    }
}

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

线程优先级(setPriority())

package org.ck.thread.status;

/**
 * @className: TestPriority
 * @description:
 * @createDate: 2021年07月07日 16:02:41
 * @author: ck
 */
public class TestPriority {

    public static void main(String[] args) {
        //主线程默认优先级
        System.out.println(Thread.currentThread().getName()+"-->"+Thread.currentThread().getPriority());
        MyPriority myPriority = new MyPriority();

        Thread t1 = new Thread(myPriority);
        Thread t2 = new Thread(myPriority);
        Thread t3 = new Thread(myPriority);
        Thread t4 = new Thread(myPriority);
        //设置优先级启动
        t1.start();
        t2.setPriority(1);
        t2.start();
        t3.setPriority(Thread.MAX_PRIORITY);
        t3.start();
    }
}
class MyPriority implements Runnable{

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

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

守护线程(setDaemon(true))

package org.ck.thread.status;

/**
 * @className: TestDaemon
 * @description: 测试守护线程
 * @createDate: 2021年07月07日 16:11:27
 * @author: ck
 */
public class TestDaemon {

    public static void main(String[] args) {
        God god = new God();
        You you = new You();

        Thread thread = new Thread(god);
        thread.setDaemon(true);//默认false为用户线程
        thread.start();//守护线程启动

        new Thread(you).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("=======hello,world");
    }
}

运行结果
在这里插入图片描述
总结:虚拟机回确保主线程执行完毕,但不会确认守护线程一定能执行完成(守护线程常有,GC)

三个不安全例子

不安全的取钱

package org.ck.thread.syn;

/**
 * @className: UnsafeBank
 * @description: 不安全的取钱
 * @createDate: 2021年07月08日 18:25:59
 * @author: ck
 */
public class UnsafeBank {

    public static void main(String[] args) {
        Account account = new Account(100,"基金");
        Drawing you = new Drawing(account,50,"你");
        Drawing youFriend = new Drawing(account,100,"你朋友");
        you.start();
        youFriend.start();
    }
}

class Account {
    int money;//余额
    String name;//卡名

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

//银行
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;
    }

    public void run() {
        //判断有没有钱
        if (account.money - drawingMoney < 0) {
            System.out.println(Thread.currentThread().getName() + "钱不够");
            return;
        }
        //sleep
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        //卡内余额 = 余额 - 你取的钱
        account.money = account.money - drawingMoney;

        nowMoney = nowMoney + drawingMoney;

        System.out.println(account.name + "余额为" + account.money);
        System.out.println(this.getName() + "手里的钱" + nowMoney);
    }
}

运行结果
在这里插入图片描述
问题:基金余额不能-50
不安全的买票

package org.ck.thread.syn;
/**
 * @className: UnsafeBuyTicket
 * @description: 不安全的买票
 *
 * @createDate: 2021年07月08日 18:18:04
 * @author: ck
 */
public class UnsafeBuyTicket {
    public static void main(String[] args) {
        BuyTicket buyTicket = new BuyTicket();
        new Thread(buyTicket, "苦逼的我").start();
        new Thread(buyTicket, "牛逼的你们").start();
        new Thread(buyTicket, "可恶的黄牛党").start();
    }
}

class BuyTicket implements Runnable {

    private int ticketNums = 10;
    boolean flag = true;//外部停止方式

    @Override
    public void run() {
        while (flag) {
            try {
                buy();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
    private void buy() throws InterruptedException {
        if (ticketNums <= 0) {
            flag = false;
            return;
        }
        Thread.sleep(100);
        System.out.println(Thread.currentThread().getName() + "拿到" + ticketNums--);
    }
}

在这里插入图片描述
问题不应该有两次1
不安全的List

package org.ck.thread.syn;

import java.util.ArrayList;
import java.util.List;

/**
 * @className: UnSafeList
 * @description: 线程不安全的集合
 * @createDate: 2021年07月08日 18:44:00
 * @author: ck
 */
public class UnSafeList {

    public static void main(String[] args) {
        List<String> list = new ArrayList<>();
        for (int i = 0; i < 10000; i++) {
            new Thread(() -> {
                //两个线程操作了同一个位置,导致有数据被覆盖了
                list.add(Thread.currentThread().getName());
            }).start();
        }
        try {
            Thread.sleep(3000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println(list.size());
    }
}

运行结果
在这里插入图片描述
问题:能明显观察到少了两个
多个线程往同一个位置插入了数据

线程安全

通过队列+锁来实现多线程的安全

安全的取钱

package org.ck.thread.syn;

/**
 * @className: UnsafeBank
 * @description: 不安全的取钱
 * @createDate: 2021年07月08日 18:25:59
 * @author: ck
 */
public class UnsafeBank {

    public static void main(String[] args) {
        Account account = new Account(100, "基金");
        Drawing you = new Drawing(account, 50, "你");
        Drawing youFriend = new Drawing(account, 100, "你朋友");
        you.start();
        youFriend.start();
    }
}

class Account {
    int money;//余额
    String name;//卡名

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

//银行
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;
    }

    public void run() {
        synchronized (account) {
            //判断有没有钱
            if (account.money - drawingMoney < 0) {
                System.out.println(Thread.currentThread().getName() + "钱不够");
                return;
            }
            //sleep
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            //卡内余额 = 余额 - 你取的钱
            account.money = account.money - drawingMoney;

            nowMoney = nowMoney + drawingMoney;

            System.out.println(account.name + "余额为" + account.money);
            System.out.println(this.getName() + "手里的钱" + nowMoney);
        }
    }
}

总结:是用户发起的取钱行为那就锁用户,让请求的用户排好队。
安全的买票

package org.ck.thread.syn;


/**
 * @className: UnsafeBuyTicket
 * @description: 不安全的买票
 *
 * @createDate: 2021年07月08日 18:18:04
 * @author: ck
 */
public class UnsafeBuyTicket {
    public static void main(String[] args) {
        BuyTicket buyTicket = new BuyTicket();
        new Thread(buyTicket, "苦逼的我").start();
        new Thread(buyTicket, "牛逼的你们").start();
        new Thread(buyTicket, "可恶的黄牛党").start();
    }
}

class BuyTicket implements Runnable {

    private int ticketNums = 10;
    boolean flag = true;//外部停止方式

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

    //synchronized 同步方法 锁的是this
    private synchronized void buy() throws InterruptedException {
        //判断是否有票
        if (ticketNums <= 0) {
            flag = false;
            return;
        }
        //模拟延时
        Thread.sleep(100);
        //买票
        System.out.println(Thread.currentThread().getName() + "拿到" + ticketNums--);
    }
}

安全的集合

package org.ck.thread.syn;

import java.util.ArrayList;
import java.util.List;

/**
 * @className: UnSafeList
 * @description: 线程不安全的集合
 * @createDate: 2021年07月08日 18:44:00
 * @author: ck
 */
public class UnSafeList {

    public static void main(String[] args) {
        List<String> list = new ArrayList<>();
        for (int i = 0; i < 10000; i++) {
            new Thread(() -> {
                //两个线程操作了同一个位置,导致有数据被覆盖了
                synchronized (list) {
                    list.add(Thread.currentThread().getName());
                }
            }).start();
        }
        try {
            Thread.sleep(3000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println(list.size());
    }
}

死锁

package org.ck.thread.syn;
/**
 * @className: DeadLock
 * @description: 死锁
 * @createDate: 2021年07月15日 10:03:12
 * @author: ck
 */
public class DeadLock {
    public static void main(String[] args) {
        Makeup girl = new Makeup(0,"灰姑凉");
        Makeup girl1 = new Makeup(1,"白雪公主");
        girl.start();
        girl1.start();
    }
}

class Lipstick {

}

class Mirror {

}

class Makeup extends Thread {

    static Lipstick lipstick = new Lipstick();
    static Mirror mirror = new Mirror();

    int choice;//选择

    String girlName;

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

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

    //化妆 互相持有对方的锁
    private 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 + "获得口红的锁");
                }
            }
        }
    }
}

在这里插入图片描述
灰姑凉想获得镜子
白雪公主想要获得口红
但是镜子在白雪公主手上
口红在灰姑凉手上
就造成了死锁
解决方案:白雪公主和灰姑凉用完各自的东西,将其放回去就不会死锁了。

 private 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 org.ck.thread.lock;

import java.util.concurrent.locks.ReentrantLock;

/**
 * @className: TestLock
 * @description:
 * @createDate: 2021年07月16日 18:12:23
 * @author: ck
 */
public class TestLock {

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

class TestLock2 implements Runnable {

    int ticketNums = 10;

    //定义lock锁
    ReentrantLock lock = new ReentrantLock();

    @Override
    public void run() {
        while (true) {
            try {
                lock.lock();
                if (ticketNums > 0) {
                    try {
                        Thread.sleep(1000);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    System.out.println(ticketNums--);
                } else {
                    break;
                }
            }finally {
                //解锁
                lock.unlock();
            }

        }
    }
}

运行结果
在这里插入图片描述
synchronized和Lock的差异
synchronized
java 关键字
会自动释放锁
lock
只是一个类
需要手动释放锁
lock相比synchronize的可操作性更强

总结

package org.ck.thread;

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

/**
 * @className: ThreadNew
 * @description: 回顾线程的创建
 * @createDate: 2021年07月19日 11:26:59
 * @author: ck
 */
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();
        Integer integer = null;
        try {
            integer = futureTask.get();
        } catch (InterruptedException e) {
            e.printStackTrace();
        } catch (ExecutionException e) {
            e.printStackTrace();
        }
        System.out.println(integer);
    }
}
//1.继承Thread类
class MyThread1 extends Thread{

    public void run(){
        System.out.println("MyThread1");
    }
}
//2.实现Runnable接口
class MyThread2 implements Runnable{

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

//实现CallAble
class MyThread3 implements Callable<Integer> {

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

以上内容学自B站狂神JAVA
https://www.bilibili.com/video/BV1V4411p7EF?from=search&seid=13950488010332720509



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


扫一扫关注最新编程教程