多线程详解

1.继承Thread类

package duoxiancheng;
/*创建线程方式一:
1.继承Thread类
2.重写run()方法
3.调用start开启线程

run()方法是先进行run()方法再进行主线程
start()方法是主线方法和start()方法同步进行

* */
public class Demo01TestThread extends Thread{
    public void run(){
        for (int i = 0; i < 20; i++) {
            System.out.println("我正在看代码"+i);
        }
    }

    public static void main(String[] args) {
        new Demo01TestThread().start();
        for (int i = 0; i < 1000; i++) {
            System.out.println("我正在学习多线程"+i);
        }
    }

}

2.网图下载

线程不一定立即执行,看CPU安排调度(这里下载图片的顺序不一定每次都相同)

注意点:敲代码之前先下载一个commons-io-2.6.jar
奉上:
链接: https://pan.baidu.com/s/1mp_ujn5RyRqQ4TDElxfhRA?pwd=r236 提取码: r236 复制这段内容后打开百度网盘手机App,操作更方便哦

下载之后将文件复制粘贴到新建的lib包下,再右键点击lib包选择Add As Library即可

package duoxiancheng;


import org.apache.commons.io.FileUtils;

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

public class Demo02TestThread2 extends Thread{
    private String url;//网络图片地址
    private String name;//保存的文件名

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

    //下载图片的执行体
    @Override
    public void run() {
        WebDownload webDownload = new WebDownload();
        webDownload.downloader(url,name);
        System.out.println("下载了文件名为:"+name);
    }

    public static void main(String[] args) {
        Demo02TestThread2 t1 = new Demo02TestThread2("https://t7.baidu.com/it/u=1732966997,2981886582&fm=193&f=GIF","1.jpg");
        Demo02TestThread2 t2 = new Demo02TestThread2("https://t7.baidu.com/it/u=1732966997,2981886582&fm=193&f=GIF","2.jpg");
        Demo02TestThread2 t3 = new Demo02TestThread2("https://t7.baidu.com/it/u=1732966997,2981886582&fm=193&f=GIF","3.jpg");

        //先下载t1,然后t2、最后是t3
        t1.start();
        t2.start();
        t3.start();


    }

}
class WebDownload{
    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异常,downloader方法出现问题");
        }
    }


}

3实现runnable接口

继承Thread类:
1.子类继承Thread类具备多线程能力
2.启动线程:子类对象.start()
3.不建议使用:避免OOP单继承局限性

实现Runnable接口:
1.实现Runnable具多线程能力
2.启动线程:传入目标对象+Thread对象.start()
3.推荐使用:避免单继承局限性,灵活方便,方便同一个对象被多个线程使用

package duoxiancheng;

public class Demo03TestThread3 implements Runnable{
    //下载图片的执行体
    @Override
    public void run() {
        for (int i = 0; i < 200; i++) {
            System.out.println("我在看代码"+i);
        }
    }

    public static void main(String[] args) {
        //创建runnnable接口的实现类对象
        Demo03TestThread3 demo03TestThread3 = new Demo03TestThread3();
        //创建线程对象,通过线程对象来开启我们的线程

        new Thread(demo03TestThread3).start();


        for (int i = 0; i < 1000; i++) {
            System.out.println("我在学习多线程"+i);
        }


    }
}

4初识并发问题

发现问题:多个线程操作同一个资源的情况下,线程不安全,有可能两个人同时抢到一个票,数据紊乱

package duoxiancheng;
/*多个线程操作同一个对象
买火车票的例子
*
* */
public class Demo04TestThread4 implements Runnable{
    private int tickNums=10;
    public void run(){

        while (true){
            //如果没票了就推出执行
            if (tickNums<=0){
                break;
            }
            //模拟延时
            try {
                Thread.sleep(200);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }

            System.out.println(Thread.currentThread().getName()+"拿到了第"+tickNums--+"票");
        }
    }
    public static void main(String[] args) {
        Demo04TestThread4 demo04TestThread4 = new Demo04TestThread4();

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


    }

}

5龟兔赛跑

package duoxiancheng;

public class Demo05Race implements Runnable{
    private static String winner;

    @Override
    public void run() {
        for (int i = 0; i <= 100; i++) {
            //让兔子睡觉,模拟延时,让兔子跑十步休息一下
            if (Thread.currentThread().getName().equals("兔子")&&i%10==0){
                try {
                    Thread.sleep(10);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
            boolean flag=gameOver(i);
            if (flag){
                break;
            }

            System.out.println(Thread.currentThread().getName()+"跑了"+i+"步");


        }
    }

    //游戏的胜利者的规则
    private boolean gameOver(int steps){
        if (winner!=null){
            return true;
        }{
            if (steps==100){
               winner=Thread.currentThread().getName();
                System.out.println("winner is "+winner);
            }
        }
        return false;
    }

    //主程序
    public static void main(String[] args) {
        Demo05Race demo05Race = new Demo05Race();

        new Thread(demo05Race,"兔子").start();
        new Thread(demo05Race,"乌龟").start();
    }
}

6实现Callable接口

package duoxiancheng;

import java.util.concurrent.*;

/*多线程创建方式之一:实现Callable接口
*Callable的好处:相比较于Thread会多出来一个返回值(布尔值),可以定义返回值,可以抛出异常
* */
public class Demo06Callable implements Callable<Boolean> {
    private String url;//网络图片地址
    private String name;//保存的文件名

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

    //下载图片的执行体
    @Override
    public Boolean call() {
        WebDownload webDownload = new WebDownload();
        webDownload.downloader(url,name);
        System.out.println("下载了文件名为:"+name);
        return true;
    }

    public static void main(String[] args) throws ExecutionException, InterruptedException {
        Demo06Callable t1 = new Demo06Callable("https://t7.baidu.com/it/u=1732966997,2981886582&fm=193&f=GIF","1.jpg");
        Demo06Callable t2 = new Demo06Callable("https://t7.baidu.com/it/u=1732966997,2981886582&fm=193&f=GIF","2.jpg");
        Demo06Callable t3 = new Demo06Callable("https://t7.baidu.com/it/u=1732966997,2981886582&fm=193&f=GIF","3.jpg");

        //创建执行服务
        ExecutorService ser= Executors.newFixedThreadPool(3);//执行者服务、执行者的新的下一个固定的线程池
        //提交执行
        Future<Boolean> submit = ser.submit(t1);
        Future<Boolean> submit1 = ser.submit(t2);
        Future<Boolean> submit2 = ser.submit(t3);
        //获取结果
        Boolean aBoolean = submit.get();
        Boolean aBoolean1 = submit1.get();
        Boolean aBoolean2 = submit2.get();
        System.out.println(aBoolean);
        System.out.println(aBoolean1);
        System.out.println(aBoolean2);
        //关闭服务
        ser.shutdownNow();

    }
}

7静态代理模式()

package duoxiancheng.lib;
/*静态代理模式总结:
真实对象和代理对象都要实现同一个接口
代理对象要代理真是角色
好处:代理对象可以做很多真实对象做不了的事情,真实对象就可以专注做自己的事情
* */
public class Demo07StaticProxy {
    public static void main(String[] args) {
        WeddingCompany weddingCompany = new WeddingCompany(new You());
        weddingCompany.HappyMarry();
        //new WeddingCompany(new You()).HappyMarry();
       /* new Thread(new Runnable() {
            @Override
            public void run() {
                
            }
        }).start(); 	这两个的性质其实是一样的Thread也有直线Runnable接口*/
        
    }

}

//结婚接口
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(); //输入了you,那就是目标是你进行快乐结婚,再调用你快乐结婚的方法就可以
        after();
    }

    private void after() {
        System.out.println("结婚之后收取尾款");
    }

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

8Lambda表达式(Lambda最简化函数式接口)

例子1

package duoxiancheng;

public class Demo07Lambda {
    //3.静态内部类
    static class Like2 implements ILike{

        @Override
        public void Lambda() {
            System.out.println("i like lambda2");
        }
    }


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

        iLike=new Like2();
        iLike.Lambda();


        //4.局部内部类
        class Like3 implements ILike{

            @Override
            public void Lambda() {
                System.out.println("i like lambda3");
            }
        }
        iLike=new Like3();
        iLike.Lambda();

        //5.匿名内部类,没有类的名称,必须借助接口或者父类
        iLike=new ILike() {
            @Override
            public void Lambda() {
                System.out.println("i like lambda4");
            }
        };
        iLike.Lambda();


        //6.用lambda简化
        iLike=()->{
            System.out.println("i like lambda5");
        };
        iLike.Lambda();


    }

}


//1.定义一个函数式接口(只有一个方法的接口)
interface ILike{
    void Lambda();
}
//2.实现类
class Like implements ILike{

    @Override
    public void Lambda() {
        System.out.println("i like lambda");
    }
}

例子2

package duoxiancheng;

import java.util.function.Consumer;

/*lambda接口只有有一行的时候才可以去掉包裹括号
多个参数的时候,可以去掉参数类型,例如int,String,但是需要添加括号
lambda必须是函数式接口(接口只有一个的定义方法)

lambda 相当于是匿名内部类的升级版简化
* */
public class Demo08Lambda2 {
    public static void main(String[] args) {
        ILove ilove=null;
        ilove = (a) -> {
            System.out.println("i love you");
        };
        ilove = a -> System.out.println("i love you"); //最简化

    }

}
interface ILove{
    void love(int a);
}


9线程停止(flag标志位)

1.建议线程正常停止、利用次数、不建议死循环
2.建议使用标志位、设置一个标志位
3.不要使用stop或者destroy等过时JDK不建议使用的方法

package duoxiancheng;
/*设置让线程停止
* */
public class Demo09TestStop implements Runnable{
    //设置一个标志位
    private 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) {
        Demo09TestStop demo09TestStop = new Demo09TestStop();
        new Thread(demo09TestStop).start();
        for (int i = 0; i < 1000; i++) {
            System.out.println("main"+i);
            if (i==900){
                demo09TestStop.stop();//利用标志位让线程停止、但是主线程还在继续运行
                System.out.println("线程停止了");
            }
        }


    }
}

10线程休眠(sleep)(系统时间每秒刷新)

package duoxiancheng;

import java.util.Date;

import java.text.SimpleDateFormat;
import java.util.logging.SimpleFormatter;

public class Demo10Sleep {
    public static void main(String[] args)  {
        Date date = new Date(System.currentTimeMillis());//获取系统当前时间
        while (true){
            try {
                Thread.sleep(1000);
                System.out.println(new SimpleDateFormat("HH:mm:ss").format(date));//按照格式去显示当前系统时间
                date = new Date(System.currentTimeMillis());//更新时间
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }

    }

  public static void tenDown() throws InterruptedException {
        int num=10;
        while (true){
            Thread.sleep(1000);
            System.out.println(num--);
            if (num<=0){
                break;
            }
        }
    }

}

11线程礼让(yield)

线程礼让不一定成功,主要看CPU心情

package duoxiancheng;
/*线程礼让
线程礼让不一定成功,主要看CPU心情
* */
public class Demo11Yield {
    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()+"线程已经停止");
    }
}

12线程强制执行(join)

想象一下是插队,插队以后先执行此线程,然后等这条线程执行完了以后再执行其他线程

package duoxiancheng;
/*测试join方法
想象一下是插队,插队以后先执行此线程,然后等这条线程执行完了以后再执行其他线程
* */
public class Demo12Join implements Runnable{
    @Override
    public void run() {
        for (int i = 0; i < 100; i++) {
            System.out.println("线程vip来了"+i);
        }
    }

    public static void main(String[] args) throws InterruptedException{
        Demo12Join demo12Join = new Demo12Join();
        Thread thread = new Thread(demo12Join);
        thread.start();


        for (int i = 0; i < 1000; i++) {
            if (i==200){
                thread.join();//插队
            }
            System.out.println("main"+i);
        }
    }
}

13观测线程状态(State)

注意点:线程一旦结束就不能再次执行

package duoxiancheng;
/*线程观察
注意点:线程一旦结束就不能再次执行
*
* */
public class Demo13State {
    public static void main(String[] args) throws InterruptedException {
        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);  //在跑的时候

        while (state!=Thread.State.TERMINATED){ //只要状态不是状态终止
            Thread.sleep(100);
            state=thread.getState();//更新线程
            System.out.println(state);//输出状态
        }
    }
}

14线程的优先级

  • 线程优先级范围是1-10,也可以有 MAX 和 MIN最大和最小值,但是主线程远远高于其他线程,主线程优先级为5
  • 优先级大不一定最优先、只是大概率会优先,优先级低的先运行了叫做“性能倒置”
package duoxiancheng;
/*线程优先级
* 线程优先级范围是1-10,也可以有 MAX 和 MIN最大和最小值
* 优先级大不一定最优先、只是大概率会优先
* */
public class Demo14Priority {


    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(1);
        thread2.start();

        thread3.setPriority(2);
        thread3.start();

        thread4.setPriority(3);
        thread4.start();

        thread5.setPriority(4);
        thread5.start();

        thread6.setPriority(Thread.MAX_PRIORITY);//最大优先级
        thread6.start();
    }


}
class MyPriority implements Runnable{

    @Override
    public void run() {
        System.out.println(Thread.currentThread().getName()+"  "+Thread.currentThread().getPriority());//输出线程名还有线程的优先等级
       
    }
}

15守护线程

package duoxiancheng;

/*守护线程
线程分为用户线程和守护线程
虚拟机必须要等用户线程执行完毕
虚拟机可以不用等守护线程执行完毕
后台操作日志、监控内存、垃圾回收等待
* */
public class Demo15Daemon {
    public static void main(String[] args) {
        God god = new God();
        You you = new You();

        Thread thread = new Thread(god);
        thread.setDaemon(true);//设置保护线程,默认为true
        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 < 1000; i++) {
            System.out.println("你一生都开心的活着"+i);
        }
        System.out.println("你已经挂掉了");
    }
}

16线程同步机制

多个线程操作统一资源
相当于很多个人去上厕所,于是就会有门锁的产生,是的线程安全
好处:非常安全
坏处:有可能优先级高的线程在等待优先级低的,造成性能倒置、另外线程如果一直在锁,就会造成性能缺失

17三大不安全案例

案例一(买票)

package duoxiancheng;
/*不安全线程1
不安全的买票
线程不安全,有负数
* */
public class Demo16Unsafe1 {
    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;
        }
        Thread.sleep(1000);
        System.out.println(Thread.currentThread().getName()+"拿到"+ticketNums--);
    }
}

案例二(取钱)

package duoxiancheng;
/*不安全的银行取钱线程
*
* */
public class Demo17Unsafe2 {
    public static void main(String[] args) {
        Account account = new Account(100,"结婚基金");
        Drawing you = new Drawing(account,50,"你");
        Drawing girl = new Drawing(account,50,"女朋友");

        you.start();
        girl.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);//有参构造super必须放在第一行
        this.account=account;
        this.drawingMoney=drawingMoney;




    }

    @Override
    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);
        //Thread.currentThread().getName()与这里的this一样
        System.out.println(this.getName()+"手里的钱"+nowMoney);

        super.run();
    }
}

案例三(数组)

package duoxiancheng;

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

public class Demo18Unsafe3 {
    public static void main(String[] args) throws InterruptedException {
        List<String> list = new ArrayList<String>();
        for (int i = 0; i < 1000; i++) {
            new Thread(()->{
                list.add(Thread.currentThread().getName());
            }).start();
        }
        Thread.sleep(1000);
        System.out.println(list.size());
    }
}

18同步方法及同步块(线程错误解决方法)

推荐使用共享资源作为同步监视器,但是它本身是可以锁定任何对象的,
同步方法中无序指定同步监视器,因为同步方法的同步监视器就是this,就是这个对象本身,或者是class【反射中讲解】
同步监视器的执行过程:
1.第一个线程访问,锁定同步监视器,执行其中代码。
2.第二个线程访问,发现同步监视器被锁定,无法访问。
3.第一个线程访问完毕,解锁同步监视器。
4.第二个线程访问,发现没有同步监视器锁定,然后开始访问然后再次锁定。

在这里插入代码片

19三大案例同步锁解决情况

案例一(买票)

package duoxiancheng;
/*不安全线程1
不安全的买票
线程不安全,有负数
* */
public class Demo16Unsafe1 {
    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; //这里一定要return,不然就算加了同步锁还是会有负数的情况发生
        }
        Thread.sleep(1000);
        System.out.println(Thread.currentThread().getName()+"拿到"+ticketNums--);
    }
}

案例二(取钱)

package duoxiancheng;

public class Demo17Usafe2 {
    public static void main(String[] args) {
        Account account = new Account(100,"结婚基金");
        Drawing you = new Drawing(account,50,"你");
        Drawing girl = new Drawing(account,50,"女朋友");

        you.start();
        girl.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);//有参构造super必须放在第一行
        this.account=account;
        this.drawingMoney=drawingMoney;
    }
    //线程的运行
    @Override
    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);
            //Thread.currentThread().getName()与这里的this一样
            System.out.println(this.getName()+"手里的钱"+nowMoney);

            super.run();
        }

    }
}

案例三(数组)

package duoxiancheng;

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

public class Demo18Unsafe3 {
    public static void main(String[] args) throws InterruptedException {
        List<String> list = new ArrayList<String>();
        for (int i = 0; i < 1000; i++) {
            new Thread(()->{
                synchronized (list){
                    list.add(Thread.currentThread().getName());
                }

            }).start();
        }
        Thread.sleep(1000);
        System.out.println(list.size());
    }
}

20(安全类型集合) CopyOnWriteArrayList

相当于是更加安全的list集合

package duoxiancheng;

import java.util.List;
import java.util.concurrent.CopyOnWriteArrayList;

/*测试JUC安全类型的集合(安全列表)
*
* */
public class Demo19JUC {
    public static void main(String[] args) {
        CopyOnWriteArrayList<String> list = new CopyOnWriteArrayList<String>();
        for (int i = 0; i < 1000; i++) {
            new Thread(()->{
                list.add(Thread.currentThread().getName());
            }).start();
        }
        //延迟
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        //输出数组的大小
        System.out.println(list.size());
    }

}

21死锁(synchronized )

package duoxiancheng;

public class Demo20Lock {
    public static void main(String[] args) {
        MakeUp makeUp = new MakeUp(0,"灰姑娘");
        MakeUp makeUp1 = new MakeUp(1,"白雪公主");

        makeUp.start();
        makeUp1.start();
    }
}
//镜子
class Mirror{

}
//口红
class Lipstick{

}
//化妆
class MakeUp extends Thread{
    //需要的资源只有一份,所以用static保证只有一份
    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+"获得镜子的锁");
                Thread.sleep(1000);
            }
        }else {
            synchronized (mirror){
                System.out.println(this.girlName+"获得镜子的锁");
                Thread.sleep(2000);
            }
        synchronized (lipstick){
            System.out.println(this.girlName+"获得口红的锁");
            Thread.sleep(1000);
        }
        }
    }

}

//线程


22Lock安全锁(ReentrantLock)

Lock只有锁,而synchronized 有代码锁块和方法锁,所以用Lock的话JVM将会花费更少的调度性能,并具有更好的扩展性(更多的子类)
Lock是显式锁,手动开启和关闭,synchronized 是隐式锁,出了作用域就自动释放
优先使用顺序:Lock>同步代码块(已经进入了方法体,分配了相应的资源)> 同步方法(在方法体之外)

package duoxiancheng;

import java.util.concurrent.locks.ReentrantLock;

public class Demo21Lock2 {
    public static void main(String[] args) {
        TestLock testLock = new TestLock();

        new Thread(testLock).start();
        new Thread(testLock).start();
        new Thread(testLock).start();
    }
}

class TestLock implements Runnable{
    private int tickNums=10;

    //创建lock锁
    private final ReentrantLock lock=new ReentrantLock();

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

            }finally {
                //解锁
                lock.unlock();
            }


        }


    }
}

23测试生产者与消费者(管程法、难点)

package duoxiancheng;

import java.util.PrimitiveIterator;

/*测试生产者与消费者
利用缓冲区解决(管程法)
* */
public class Demo22PC {
    public static void main(String[] args) {
        SynContainer container = new SynContainer();

        new Productor(container).start();
        new Consumer(container).start();

    }

}

//生产者
class Productor extends Thread{
    SynContainer container;
    public Productor(SynContainer container) {
        this.container = container;
    }
    //生产
    @Override
    public void run() {
        for (int i = 0; i < 1000; i++) {
            container.push(new Chicken(i));
            System.out.println("生产了"+i+"只鸡");
        }
        super.run();
    }
}

//消费者
class Consumer extends Thread{
    SynContainer container;
    public Consumer(SynContainer container) {
        this.container = container;
    }
    //消费

    @Override
    public void run() {
        for (int i = 0; i < 100; i++) {
            System.out.println("消费了"+container.pop().id+"只鸡");
        }
    }
}
//产品
class Chicken{
    int id;
    public 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;
    }

    //消费者消费产品

}


24信号灯法

package duoxiancheng;
/*利用标志位或者容器,前一个章节生产者与消费者模式中有用到
都可以实现等待与通知
* */


//主方法类
public class Demo23PC2 {
    public static void main(String[] args) {
        TV tv = new TV();
        new Player(tv).start();
        new Watch(tv).start();
    }
}



//演员类
class Player extends Thread{
    TV tv;
    public Player(TV tv) {
        this.tv = tv;
    }

    @Override
    public void run() {
        for (int i = 0; i < 20; i++) {
            if (i%2==0){
                this.tv.play("快乐大本营播放中");
            }else {
                this.tv.play("广告播放中");
            }
        }
    }
}



//观众类
class Watch extends Thread{
    TV tv;
    public Watch(TV tv) {
        this.tv = tv;
    }

    @Override
    public void run() {
        for (int i = 0; i < 20; i++) {
            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.getClass();//通知唤醒
        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.notify();
        this.flag=!flag;

    }
}

线程池

经常创建和销毁线程,对性能的影响很大
思路:提前创建好很多的线程放在池子中,使用时直接获取,用完再放回池子中,可以避免重复的创建销毁,实现重复利用。
好处:1.提高效应速度(减少了创建的时间)2.降低资源消耗(直接获取池中的线程,不需要每次都创建)3.便于线程管理
3.1在这里插入图片描述

package duoxiancheng;

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

public class Demo24Pool {
    public static void main(String[] args) {
        //创建服务,创建线程池
        //newFixedThreadPool    参数为:线程池大小
        ExecutorService service= Executors.newFixedThreadPool(10);

        //执行
        service.execute(new MyThread());
        service.execute(new MyThread());
        service.execute(new MyThread());
        service.execute(new MyThread());


        //关闭链接
        service.shutdownNow();

    }

}

class MyThread implements Runnable{

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

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值