Java多线程(全)

多线程

1.程序、进程、线程

  • 在操作系统中运行的程序就是进程;

  • 一个进程可以有多个线程;

  • 程序是指令和数据的有序集合,是一个静态的概念;

  • 而进程则是执行程序的一次执行过程,是一个动态的概念;

  • 进程是系统资源分配的单位

  • 线程是CPU调度和执行的单位

  • 真正的多线程是指多个cpu,即多核

理解:进程相当于一个类,类中有多个方法(即多个线程),main()方法即(主线程),gc线程。

  • main()方法即(主线程)为系统的入口,用于执行整个程序;
  • 线程的运行是由调度器安排调度,不能人为干预;
  • 对同一份资源操作时,会存在资源抢夺的问题,需要加入并发控制
  • 线程会带来额外的开销,如cpu的调度时间,并发控制开销
  • 每个线程在自己的工作内存交互,内存控制不当会造成数据不一致

2.线程的创建

  1. 三种创建方式

    • Thread class

      • 继承Thread类
    • Runnable接口

      • 实现Runnable接口
    • Callable接口

      • 实现Callable接口

3.Thread

  • 自定义类继承Thread
  • 重写run()方法;
  • 创建对象,调用start()开启线程
import javax.xml.transform.Source;

public class TestThread01 extends Thread{
    //继承Thread类
//总结:线程开启不一定立即执行,有CPU调度执行

    @Override
    public void run() {
        //run()方法线程体
        for (int i = 0; i < 20; i++) {
            System.out.println("**********-4564646465");
        }
    }

    //main线程,即主线程
    public static void main(String[] args) {

        TestThread01 testThread01 = new TestThread01();

        //testThread01.start();//线程开启,交替(类似同时)执行,电脑单核只有一个cpu

        testThread01.run();//这个在前,先执行run();

        for (int i = 0; i < 20; i++) {
            System.out.println("7554574545*********");
        }

    }


}

多线程实现多张图片同时下载

import org.apache.commons.io.FileUtils;

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

public class TestThread02 extends Thread{
    private String url;
    private  String name;

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

    @Override
    public void run() {
       //下载线程
        WebDownloader webDownloader = new WebDownloader();
        try {
            webDownloader.downloader(url,name);
            System.out.println(name);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    public static void main(String[] args) {
        TestThread02 testThread02 = new TestThread02("https://timgsa.baidu.com/timg?image&quality=80&size=b9999_10000&sec=1603037822768&di=5f0cc79b7c104781de8cea48c7d8b1ca&imgtype=0&src=http%3A%2F%2Fattach.bbs.miui.com%2Fforum%2Fmonth_1012%2F10120514509c7244b23f4a2fa5.jpg","a.jpg");
        TestThread02 testThread03 = new TestThread02("https://ns-strategy.cdn.bcebos.com/ns-strategy/upload/fc_big_pic/part-00720-1746.jpg","a1.jpg");
        TestThread02 testThread04 = new TestThread02("https://ss2.bdstatic.com/70cFvnSh_Q1YnxGkpoWK1HF6hhy/it/u=2441956749,4275399915&fm=26&gp=0.jpg","a2.jpg");
        testThread02.start();
        testThread03.start();
        testThread04.start();
    }

}
//下载器
class WebDownloader{
    //下载方法
    public  void  downloader(String url,String name) throws IOException {

        FileUtils.copyURLToFile(new URL(url),new File(name));

    }
}

4.Runnable

推荐使用Runnable对象,因为Java单继承的局限性

  1. 定义MyRunnable类实现Runnable接口
  2. 实现run()方法,编写线程执行体
  3. 创建线程对象,调用start()方法启动线程
public class TestRunnable01 implements Runnable{

    public void run() {
        for (int i = 0; i < 20; i++) {
            System.out.println("*******************");
        }
    }

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

5.小结

  • 继承Thread

    • 子类继承Thread类具备多线程能力
    • 启动线程:子类对象.start()
    • 不建议使用:避免OOP单继承局限性
  • 实现Runnable接口

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

多个线程操作同一个资源问题

//多个线程操作同一个资源
//模拟买票

//发现问题:多个线程操作同一个人资源的情况下,线程不安全,数据紊乱。

public class TestRunnable02 implements Runnable{

    private  int ticket=10;


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

        }
    }

    public static void main(String[] args) {
        TestRunnable02 runnable02=new TestRunnable02();
        new Thread(runnable02,"小鹏").start();
        new Thread(runnable02,"小强").start();
        new Thread(runnable02,"小慧").start();
    }
}

6.实例:龟兔赛跑

import org.omg.Messaging.SyncScopeHelper;

public class Race implements Runnable{

    private static String winner;


    public void run() {
        for (int i = 0; i <= 100; i++) {

            //模拟兔子睡觉
            if (Thread.currentThread().getName().equals("兔子")&&i%50==0){
                try {
                    Thread.sleep(1);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }

            //判断100步
            if (win(i)){
                break;
            }
            System.out.println(Thread.currentThread().getName()+"跑了"+i+"步");
        }
    }

    //判断胜利者
    public boolean win(int step){
        if (winner!=null){
            return true;
        }
        if (step>=100){
            winner=Thread.currentThread().getName();
            System.out.println("胜利者是"+winner);

        }

        return false;
    }

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

7.Callable

8.静态代理模式

//静态代理模式总结:
//真实对象和代理对象都要实现同一个接口
//代理对象要代理真实对象

//好处:
//代理对象可以做很多真实对象做不了的事情
//真实对象专注做自己的事情

public class StaticProxy {
    public static void main(String[] args) {
       WeCompany weCompany=new WeCompany(new You());
       weCompany.HappyMarry();

    }
}

interface Marry{
    void HappyMarry();
}

class You implements Marry{

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

}

class WeCompany implements  Marry{
    private  Marry marry;

    public WeCompany(Marry marry) {
        this.marry = marry;
    }

    public void HappyMarry() {
        before();
        this.marry.HappyMarry();
        after();
    }
    public void before(){
        System.out.println("结婚之前,布置现场");
    }
    public void after(){
        System.out.println("结婚之后,收尾款");
    }
}

9.Lamda表达式

  1. 函数式接口:只有一个抽象方法的接口

  2. 对于函数式接口,我们可以通过lambda表达式来创建该接口的对象

  3. lambda推导过程代码

    import java.awt.peer.LabelPeer;
    
    /*
    推到lambda表达式
     */
    public class TestLambda {
    
        //3.静态内部类
        static class Like2 implements ILikeLamb{
            public void lambda() {
                System.out.println("i like lambda2***");
            }
        }
    
        public static void main(String[] args) {
            //方式1使用外部类
            ILikeLamb like  = new Like1();
            like.lambda();
            //方式2使用静态内部类
            like=new Like2();
            like.lambda();
    
    
            //4.局部内部类
            class Like3 implements ILikeLamb{
    
                public void lambda() {
                    System.out.println("i like lambda3!!!");
                }
            }
    
            //方式3使用局部内部类
            like=new Like3();
            like.lambda();
    
            //5.匿名内部类
            like=new ILikeLamb() {
                public void lambda() {
                    System.out.println("i like lambda4~~~~~~");
                }
            };
            //方式4使用匿名内部类
            like.lambda();
    
            //6.lambda表达式
    
            like=() ->  {
                    System.out.println("i like lambda5~***~~");
            };
            //方式5使用lambda表达式
            like.lambda();
    
    
        }
    }
    
    
    //1.定义一个函数式接口
    interface ILikeLamb{
        void lambda();
    }
    //2.实现类
    class Like1 implements ILikeLamb{
        public void lambda() {
            System.out.println("i like lambda");
        }
    }
    

    lambda简化

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

         //局部内部类
         class Love implements ILove{
             @Override
             public void live(int a) {
                 System.out.println("i love number is"+a);
             }
         }
         ILove love=new Love();
         love.live(666);

         //匿名内部类
         love=new ILove() {
             @Override
             public void live(int a) {
                 System.out.println("i love number is"+a);
             }
         };
         love.live(888);

         //lambda表达式
         love=(int a)-> {
                 System.out.println("i love number is"+a);
         };
         love.live(999);


         //简化1,去参数类型
         love=(a)-> {
             System.out.println("i love number is"+a);
         };
         //简化2.去括号
         love=a-> {
             System.out.println("i love number is"+a);
         };
         //简化3.去花括号
         love = a -> System.out.println("i love number is"+a);

         //总结:
            //方法中只有一行代码才可以简化花括号,多行得用{};
            //前提接口必须是函数式接口;
            //多个参数得同时都去掉类型,却得用()括起来(a,b,c);


         }

     }


interface ILove{
    public void live(int a);
}


10.线程状态

五种状态

在这里插入图片描述

两张图对比理解

在这里插入图片描述

11.线程方法

在这里插入图片描述

12.线程停止

在这里插入图片描述

自定义停止代码

public class ThreadStop implements Runnable{

    private boolean flg=true;


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

    public static void main(String[] args) {

        ThreadStop threadStop=new ThreadStop();
        new Thread(threadStop).start();

        for (int i = 0; i < 500; i++) {
            System.out.println("main线程"+i);
            if (i==444){
                threadStop.stop();
                System.out.println("该线程停止了***************");
            }
        }




    }

    public void stop(){
        this.flg=false;
    }
}

13.线程休眠

在这里插入图片描述

模拟倒计时

//模拟倒计时
public class ThreadSleep2 implements Runnable{
    private  int ticket=10;
    @Override
    public void run() {
        while (true){
            if (ticket <= 0) {
                break;
            }
            //模拟延时

            try {
                Thread.sleep(1000);
                System.out.println(ticket--);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }


    }

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

模拟时钟


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


//模拟时钟
import static java.lang.System.currentTimeMillis;

public class ThreadSleep3 {
    public static void main(String[] args) {
        //获取当前系统时间
        Date time= new Date(System.currentTimeMillis());

        while (true){
            try {
                Thread.sleep(1000);
                System.out.println(new SimpleDateFormat("HH:mm:ss").format(time));
                time= new Date(System.currentTimeMillis());//更新时间
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}

14.线程礼让

  • 礼让线程,让当前正在执行的线程暂停,但步阻塞
  • 将线程从运行状态转为就绪状态
  • 让CPU重新调度,礼让不一定成功!看CPU心情
//礼让不一定成功
public class ThreadYield {

    public static void main(String[] args) {
        MyYield myYield=new MyYield();

        new Thread(myYield,"aaa").start();
        new Thread(myYield,"bbb").start();
    }

}

class MyYield implements Runnable{

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

15.Join

  • Join合并线程,待此线程执行完成后,再执行其他线程,其他线程阻塞
  • 可以想象成插队
//测试join//类似于插队
public class ThreadJoin implements Runnable{
    @Override
    public void run() {
        for (int i = 0; i < 20; i++) {
            System.out.println(Thread.currentThread().getName()+"来了"+i);
        }
    }

    public static void main(String[] args) {
        ThreadJoin threadJoin = new ThreadJoin();
        Thread thread=new Thread(threadJoin,"vip");
        thread.start();

        for (int i = 0; i < 100; i++) {
            if (i==40){
                try {
                    thread.join();//强势插入,主线程阻塞
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
            System.out.println("main来了"+i);
        }

    }


}


16.线程状态观测

  • Thread.State
    
  • 线程可以处于以下状态之一:

    • NEW
      尚未启动的线程处于此状态。
    • RUNNABLE
      在Java虚拟机中执行的线程处于此状态。
    • BLOCKED
      被阻塞等待监视器锁定的线程处于此状态。
    • WAITING
      正在等待另一个线程执行特定动作的线程处于此状态。
    • TIMED_WAITING
      正在等待另一个线程执行动作达到指定等待时间的线程处于此状态。
    • TERMINATED
      已退出的线程处于此状态。

17.线程的优先级

set和get–priority()

低优先级只意味着调度概率低,并不是优先级低就不会被先调用。

测试代码

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

        System.out.println(Thread.currentThread().getName()+"--->"+Thread.currentThread().getPriority());

        MyThread myThread=new MyThread();

        Thread thread1=new Thread(myThread);
        Thread thread2=new Thread(myThread);
        Thread thread3=new Thread(myThread);
        Thread thread4=new Thread(myThread);
        Thread thread5=new Thread(myThread);

        //设置优先级
        thread1.setPriority(6);
        thread1.start();

        thread2.setPriority(2);
        thread2.start();

        thread3.setPriority(8);
        thread3.start();

        thread4.setPriority(4);
        thread4.start();

        thread5.setPriority(10);
        thread5.start();


    }
}

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

18.守护(daemon)线程

  • 线程分为用户线程和守护线程

  • 虚拟机必须确保用户线程执行完毕

  • 虚拟机不用等待守护线程执行完毕

  • 如,后台记录操作日志,监控内存,垃圾回收等

public class ThreadDaemon {
    public static void main(String[] args) {
        Gad gad=new Gad();
        Our our=new Our();

        Thread t=new Thread(gad);
        Thread t1=new Thread(our);
        
        t.setDaemon(true);//用户线程默认false
        t.start();
        
        t1.start();
    }




}

class Gad implements Runnable{
    @Override
    public void run() {
        while (true){
            System.out.println("Gad NB alone living");
        }
    }
}

class Our implements Runnable{
    @Override
    public void run() {
        for (int i = 0; i < 36500; i++) {
            System.out.println("living*********living"+i);
        }
        System.out.println("death---------death=-");
    }
}

19.线程同步

  1. 多个线程操作同一个资源

  2. 并发:同一个对象被多个线程同时操作

  3. 处理多线程问题时,多个线程访问同一个对象,并且某些线程还想修改这个对象。这时候我们就需要线程同步,线程同步其实就是一种等待机制,多个需要同时访问此对象的线程进入这个对象的等待池形成队列,等待前面的线程使用完毕,下一个线程在再使用

  4. 队列+锁:锁机制(synchronized)

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-zJT2Wokt-1603259602918)(C:\Users\Wv587-h\AppData\Roaming\Typora\typora-user-images\image-20201020163000351.png)]

性能倒置

20.三大线程不安全列子

  1. 购票;

    package safe;
    
    public class UnSafeTicket {
        public static void main(String[] args) {
            BuyTicket buy=new BuyTicket();
            new Thread(buy,"小张").start();
            new Thread(buy,"小五").start();
            new Thread(buy,"小六").start();
            new Thread(buy,"小巴").start();
        }
    
    
    }
    class BuyTicket implements Runnable{
    
        private int tickets=100;
        private boolean flag=true;
    
    
        @Override
        public void run() {
            while (flag){
                try {
                    buy();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
    
        }
    
        private void buy() throws InterruptedException {
            if (tickets<=0){
                flag=false;
                return;
            }
            Thread.sleep(100);
            System.out.println(Thread.currentThread().getName()+"拿到第"+tickets--+"票");
        }
    }
    
  2. 取款;

    package safe;
    
    import com.sun.org.apache.bcel.internal.generic.NEW;
    
    import javax.naming.Name;
    
    public class UnSafeBank {
    
        public static void main(String[] args) {
            Account account= new Account("联邦",9999999);
            Bank bank=new Bank(account,5111111);
            Bank bank2=new Bank(account,5111111);
    
            Thread t=new Thread(bank,"多多");
            t.start();
    
            Thread t2=new Thread(bank2,"零零");
            t2.start();
        }
    
    
    
    
    
    }
    class Account{
    
        private String account;
        private int money;
    
        public Account(String account, int money) {
            this.account = account;
            this.money = money;
        }
    
        public String getAccount() {
            return account;
        }
    
        public void setAccount(String account) {
            this.account = account;
        }
    
        public int getMoney() {
            return money;
        }
    
        public void setMoney(int money) {
            this.money = money;
        }
    }
    
    class Bank implements Runnable{
        Account account;
        int drawMoney;
        int nowMoney;
    
        public Bank(Account account, int drawMoney) {
    
            this.account = account;
            this.drawMoney = drawMoney;
    
        }
    
    
        @Override
        public void run() {
            if (account.getMoney()-drawMoney<0){
                System.out.println("余额不足!!!");
                return;
            }
            try {
                Thread.sleep(1000);//等待让两个线程都进来
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
    
            account.setMoney(account.getMoney()-drawMoney);
    
            nowMoney=nowMoney+drawMoney;
    
            System.out.println(Thread.currentThread().getName()+"取走了"+nowMoney);
            System.out.println(account.getAccount()+"卡上余额为:"+account.getMoney());
    
        }
    }
    
  3. 集合list;

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

21.synchronized

  • 同步方法

    package safe;
    
    public class SafeTicket {
        public static void main(String[] args) {
            BuyTicket1 buy=new BuyTicket1();
            new Thread(buy,"小张").start();
            new Thread(buy,"小五").start();
            new Thread(buy,"小六").start();
            new Thread(buy,"小巴").start();
        }
    
    
    }
    class BuyTicket1 implements Runnable{
    
        private int tickets=100;
        private boolean flag=true;
    
    
        @Override
        public void run() {
            while (flag){
                try {
                    buy();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
    
        }
    //在方法加synchronized
        private synchronized void buy() throws InterruptedException {
            if (tickets<=0){
                flag=false;
                return;
            }
            Thread.sleep(100);
            System.out.println(Thread.currentThread().getName()+"拿到第"+tickets--+"票");
        }
    }
    
    
  • 同步块

    package safe;
    
    public class SafeBank {
    
        public static void main(String[] args) {
            Account1 account= new Account1("联邦",9999999);
            Bank1 bank=new Bank1(account,5111111);
            Bank1 bank2=new Bank1(account,5111111);
    
            Thread t=new Thread(bank,"多多");
            t.start();
    
            Thread t2=new Thread(bank2,"零零");
            t2.start();
        }
    
    
    
    
    
    }
    class Account1{
    
        private String account;
        private int money;
    
        public Account1(String account, int money) {
            this.account = account;
            this.money = money;
        }
    
        public String getAccount() {
            return account;
        }
    
        public void setAccount(String account) {
            this.account = account;
        }
    
        public int getMoney() {
            return money;
        }
    
        public void setMoney(int money) {
            this.money = money;
        }
    }
    
    class Bank1 implements Runnable{
        Account1 account;
        int drawMoney;
        int nowMoney;
    
    
    
        public Bank1(Account1 account, int drawMoney) {
    
            this.account = account;
            this.drawMoney = drawMoney;
    
        }
    
    
        @Override
        public void run() {
            //同步块,锁 变化的对象
            synchronized(account){   //锁的对象就是变化的量,需要增删改
                if (account.getMoney()-drawMoney<0){
                    System.out.println("余额不足!!!");
                    return;
                }
                try {
                    Thread.sleep(1000);//等待让两个线程都进来
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
    
                account.setMoney(account.getMoney()-drawMoney);
    
                nowMoney=nowMoney+drawMoney;
    
                System.out.println(Thread.currentThread().getName()+"取走了"+nowMoney);
                System.out.println(account.getAccount()+"卡上余额为:"+account.getMoney());
    
            }
    
            }
    
    }
    
  • 对比JUC

    package safe;
    
    import java.util.concurrent.CopyOnWriteArrayList;
    
    //测试JUC安全类型的集合
    public class TestJUC {
        public static void main(String[] args) throws InterruptedException {
            CopyOnWriteArrayList<String> co=new CopyOnWriteArrayList<String>();
            for (int i = 0; i < 1000; i++) {
                new Thread(()->{
                    co.add(Thread.currentThread().getName());
                }).start();
            }
            Thread.sleep(2000);
            System.out.println(co.size());
        }
    }
    
    

22.死锁

  • 多个线程各自占有一些资源,并且互相等待其他线程占有的资源才能运行,而导致两个过着多个线程都在等待对方释放资源,都停止执行的情况
package thread;


//多个资源互相抱着对方的资源,形成僵持
public class DeadLock {

    public static void main(String[] args) {
        Makeup makeup=new Makeup(0,"小红");
        Makeup makeup1=new Makeup(1,"大蓝");

        makeup.start();
        makeup1.start();

    }
}

class Lipstick{

}

class Mirror{

}

class Makeup extends Thread{

    //static确保资源唯一
    static private Lipstick lipstick=new Lipstick();
    static private Mirror mirror=new Mirror();

    int choose;
    String name;

    public Makeup(int choose, String name) {
        this.choose = choose;
        this.name = name;
    }

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

    private void makeup() throws InterruptedException {
        if (choose==0){
            synchronized (lipstick){
                System.out.println(this.name+"拿到口红!!");
                Thread.sleep(1000);
                synchronized (mirror){
                    System.out.println(this.name+"拿到镜子!!!");
                }

            }

            /*synchronized (mirror){
                System.out.println(this.name+"拿到镜子!!!");
            }*/

        }else {
            synchronized (mirror){
                System.out.println(this.name+"拿到镜子!!");
                Thread.sleep(2000);
                synchronized (lipstick){
                    System.out.println(this.name+"拿到口红!!!");
                }
            }
           /* synchronized (lipstick){
                System.out.println(this.name+"拿到口红!!!");
            }*/
        }
    }
}
  • 产生死锁的四个必要条件
    • 互斥条件:一个资源每次只能被一个进程使用。
    • 请求与保持条件:一个进程因请求资源而阻塞是,对已获得的资源保持不放。
    • 不剥夺条件:进程以获得的资源,在未使用完之前,不能强行剥夺。
    • 循环等待条件:若干进程之间形成一种头尾相接的循环等待资源关系。

上面列出的四个条件,只要想办法破其中的任意一个或多个就可以避免死锁发生

23.Lock

  1. 从JDK5.0开始,Java提供了更强大的线程同步机制——通过显式定义同步锁对象来实现同步。同步锁使用Lock对象充当

  2. java.util.concurrent.locks.Lock接口是控制多个线程对共享资源进行访问的工具。

  3. 锁提供了对共享资源的独占访问,每次只能有一个线程对Lock对象加锁,线程开始访问共享资源之前应先获得Lock对象

  4. ReentrantLock类实现了Lock,它拥有与synchronized相同的并发性和内存语义,在实现线程安全的控制中,比较常用的是ReentrantLock,可以显式加锁、释放锁。

    Lock的使用

在这里插入图片描述

测试代码

package safe;

import java.util.concurrent.locks.ReentrantLock;

public class TestLock {
    public static void main(String[] args) {
        TicketLock ti=new TicketLock();
        new Thread(ti).start();
        new Thread(ti).start();
        new Thread(ti).start();
    }

}

class TicketLock implements Runnable{

    int ticket=10;

    private final ReentrantLock lock=new ReentrantLock();//创建锁对象
    @Override
    public void run() {
        while (true) {


            try {
                lock.lock();//加锁
                if (ticket > 0) {
                    try {
                        Thread.sleep(100);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    System.out.println(ticket--);

                } else {
                    return;

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


        }
    }
}

synchronized与Lock的对比

  • Lock是显式锁(手动开启和关闭锁,别忘记关闭锁) synchronized是隐式锁,出了作用域自动释放

  • Lock只有代码块锁,synchronized有代码块锁和方法锁

  • 使用Lock锁,JVM将花费较少的时间来调度线程,性能更好。并且具有更好的扩展性(提供更多的子类)

  • 优先使用顺序:

    • Lock >同步代码块(已经进入了方法体,分配了相应资源)>同步方法(在方法体之外)

24.生产者消费者

代码

package safe;

import java.util.LinkedList;

public class TestPC {
    //最大容量
    public static final int MAX_SIZE = 10;
    //存储媒介
    public static LinkedList<Integer> list = new LinkedList<>();

    class Producer implements Runnable {
        @Override
        public void run() {
            synchronized (list) {
                //仓库容量已经达到最大值
                while (list.size() == MAX_SIZE) {
                    System.out.println("仓库已满,生产者" + Thread.currentThread().getName() + "不可生产.");
                    try {
                        list.wait();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
                list.add(1);
                System.out.println("生产者" + Thread.currentThread().getName() + "生产, 仓库容量为" + list.size());
                list.notify();
            }
        }
    }

    class Consumer implements Runnable {

        @Override
        public void run() {
            synchronized (list) {
                while (list.size() == 0) {
                    System.out.println("仓库为空,消费者" + Thread.currentThread().getName() + "不可消费.");
                    try {
                        list.wait();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
                list.removeFirst();
                System.out.println("消费者" + Thread.currentThread().getName() + "消费,仓库容量为" + list.size());
                list.notify();
            }
        }
    }


    public static void main(String[] args) {
        TestPC pc = new TestPC();
        Producer producer = pc.new Producer();
        Consumer consumer = pc.new Consumer();

        for (int i = 0; i < 10; i++) {
            Thread pro = new Thread(producer,"P");
            pro.start();
            Thread con = new Thread(consumer,"C");
            con.start();
        }
    }

}

25.线程池

使用线程池

在这里插入图片描述

代码

package thread;

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

public class ThreadPool {


    public static void main(String[] args) {

        //创建服务,创建线程池,newFixedThreadPool,参数:个数
        ExecutorService service= Executors.newFixedThreadPool(5);

        service.execute(new MyThread1());
        service.execute(new MyThread1());
        service.execute(new MyThread1());
        service.execute(new MyThread1());
        service.execute(new MyThread1());

        //关闭服务
        service.shutdown();
    }
}

class MyThread1 implements Runnable{

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

26.总结

三种方法

package thread;

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

public class ThreadNew {

    public static void main(String[] args) throws ExecutionException, InterruptedException {

        //1
        Thread1 t1=new Thread1();
        t1.start();

        //2.
        Thread2 t2=new Thread2();
        new Thread(t2).start();

        FutureTask<Integer> task=new FutureTask<Integer>(new Thread3());
        new Thread(task).start();
        Integer integer=task.get();
        System.out.println(integer);
    }
}

//1.继承Thread
class Thread1 extends Thread{
    public void run(){
        System.out.println("Thread111");
    }
}
//2.实现Runnable
class Thread2 implements Runnable{
    @Override
    public void run() {
        System.out.println("thread222");
    }
}

//3.实现Callable
class Thread3 implements Callable<Integer>{
    @Override
    public Integer call() throws Exception {
        System.out.println("thread3333");
        return 100;
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值