• Java多线程完结!!!


    线程状态(20-12-09)

    new -->就绪状态 <-->运行状态-->dead

    阻塞状态-->就绪状态<-->运行状态-->阻塞状态

    停止线程:

    不推荐使用JDK提供的stop()、destroy()方法

    推荐线程自己停止下来

    建议使用一个标志位进行终止变量,当flag=false,则终止线程运行

    线程休眠

    sleep(时间)指定当前线程阻塞的毫秒数

    sleep存在异常InterruptedException

    sleep时间达到后线程进入就绪状态

    sleep可以模拟网络延时,倒计时等

    每一个对象都有一个锁,sleep不会释放锁

    线程礼让 yield

    礼让线程,让当前正在执行的线程暂停,但不阻塞

    将线程从运行状态转为就绪状态

    让CPU重新调度,礼让不一定成功!看CPU心情

    线程强行执行 join

    join合并线程,待此线程执行完成后,再执行其他线程,其他线程阻塞

    可以想象成插队

    线程状态观测 state

    Thread.State;//五大状态
    

    线程优先级 priority

    优先级低只是意味着获得调度的概率低,并不是优先级低就不会被调度了。这都是看CPU的调度

    守护线程 daemon

    线程分为用户和守护线程

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

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

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

    线程同步(20-12-09)

    线程安全 synchronized

    线程同步:多个线程操作同一个资源

    例.线程不安全的集合

    public static void main(String[] args) {
            List<String> list=new ArrayList<String>();
            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());
        }
    

    同步方法:synchronized 方法 和 synchronized 块

    前者直接在方法上加就可以;后者要把方法体包在synchronized 块中

    锁的对象就是变化的量,需要增删改的对象!!!

    或使用本身就是安全的类 CopyOnWriteArrayList

    public static void main(String[] args) {
            CopyOnWriteArrayList<String> list=new CopyOnWriteArrayList<String>();
            //CopyOnWriteArrayList本身就是线程安全的
            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());
        }
    

    死锁(20-12-09)

    死锁:多个线程互相抱着对方需要的资源,然后形成僵持

    死锁第四个必要条件:

    1.互斥条件:一个资源每次只能被一个进程使用。
    2.请求与保持条件: 一个进程因请求资源而阻塞时,对已获得的资源保持不放。
    3.不剥夺条件 :进程已获得的资源,在未使用完之前,不能强行剥夺。
    4.循环等待条件:若干进程之间形成一种头尾相接的循环等待资源关系。

    Lock(锁)

    实例

    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锁
        private final ReentrantLock lock=new ReentrantLock();
    
        @Override
        public void run() {
            while (true){
               try {//加锁要使用try finally
                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 的对比

    Lock是显式锁(手动开启和关闭锁,别忘记关闭锁) synchronized是隐式锁, 出了
    作用域自动释放
    Lock只有代码块锁,syrichronized有代码块锁和方法锁
    使用Lock锁,JVM将花费较少的时间来调度线程,性能更好。并且具有更好的扩展
    性(提供更多的子类)
    优先使用顺序:
    Lock >同步代码块(已经进入了方法体,分配了相应资源) >同步方法(在方法体之外)

    线程通信(20-12-09)

    生产者/消费者问题

    管程法

    生产者将生产好的数据放入缓冲区,消费者从缓冲区拿出数据

    ...

    信号灯法

    设置一个标志位

    public class TestPC2 {
        public static void main(String[] args) {
            TV tv = new TV();
            new Player(tv).start();
            new Watcher(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 Watcher extends Thread{
        TV tv;
    
        public Watcher(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.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;
        }
    
    }
    

    线程池(20-12-09)

    ExecutorService:真正的线程池接口。常见子类 ThreadPoolExecutor

    Executors:工具类、线程池的工厂类,用于创建并返回不同类型的线程池

    总结

    三种线程创建

    //回顾线程创建
    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 integer=futureTask.get();
                System.out.println(integer);
            } catch (InterruptedException e) {
                e.printStackTrace();
            } catch (ExecutionException e) {
                e.printStackTrace();
            }
        }
    
    }
    
    //1.继承Thread类
    class MyThread1 extends Thread{
        @Override
        public void run() {
            System.out.println("MyThread1");
        }
    }
    
    //2.实现Runnable接口
    class MyThread2 implements Runnable{
        @Override
        public void run() {
            System.out.println("MyThread2");
        }
    }
    
    //3.实现Callable接口
    class MyThread3 implements Callable<Integer>{
        @Override
        public Integer call() throws Exception {
            System.out.println("MyThread3");
            return 100;
        }
    }
    
    本人学习Java的一片私人空间……
  • 相关阅读:
    同源策略和跨域知识点学习
    一次脚本注入广告漏洞分析
    一个利用微信分享的项目开发过程以及后续思考
    react-native —— 在Windows下搭建React Native Android开发环境
    ionic —— 开发环境搭建并编译运行第一个APP
    错误: 找不到或无法加载主类
    jekyll and github.io搭建博客遇到的问题
    java 10 生成头文件
    JNI的使用
    vivado error:incorrect freePtr. Call out of sequence?
  • 原文地址:https://www.cnblogs.com/none-space/p/14111246.html
Copyright © 2020-2023  润新知