关于后端:java开发两年连这些多线程知识都还没掌握你凭什么涨薪

2次阅读

共计 5797 个字符,预计需要花费 15 分钟才能阅读完成。

并发与并行

  • 并发:两个或者多个事件在同一时间段产生(交替执行)
  • 并行:两个或者多个事件在同一时刻产生(cpu 多核、同时执行)

线程与过程

  • 过程:是一个内存中运行的应用程序,有本人独立的内存空间,一个应用程序至多有一个过程,一个过程至多有一个线程;
  • 线程:线程是过程中的一个执行单元,是 CPU 调度和分派的根本单位,能独立运行的根本单位,同一过程中的多个线程之间能够并发执行。

    线程调度:

  • 分时调度:所有线程轮流应用 CPU 的使用权,平均分配每个线程占用 CPUde 工夫
  • 抢占式调度:优先让优先级高的线程应用 cpu,如果线程的优先级雷同,就随机抉择一个线程(线程随机性);Java 应用的为抢占式调度;

主线程:

  • 单线程程序:Java 程序中只有一个线程
  • 执行从 main 办法开始,从上到下顺次执行

如何创立一个多线程

  1. 通过继承 Thead 类,java.lang.Thead; 重写 Thead 中的 run 办法,在 run 办法中设置咱们的线程工作, 调用 start() 办法,开启新的线程,执行 run 办法
public class TheadTest extends Thread{
 @Override
 public void run() {for (int i = 0; i < 10; i++){System.out.println(i);
    }
 }
TheadTest theadTest = new TheadTest();
 theadTest.start();

多线程的运行原理:

多线程内存图解:

多个线程之间是互不影响的,因为在不同的栈空间

Thred 类的罕用办法

  1. 获取线程名:
  • getName()
  • static currentThread() 返回以后正在执行的线程对象的援用。
  • Thread.currentThread().getName()
  1. 设置线程的名称:
  • setName(String name) 扭转该线程的名称等于参数 name。
  • 创立带参的构造方法
  1. static void sleep(long millis)
  • 以后正在执行的线程休眠(暂停执行)为指定的毫秒数,依据精度和零碎定时器和调度的准确性。

实现 Runnable 接口

public class RunnableThead implements Runnable {
    @Override
    public void run() {for (int i = 0; i < 5 ; i++) {System.out.println(i);
        }
    }
   RunnableThead runnableThead = new RunnableThead();
   new Thread(runnableThead).start();
  • Thread(Runnable target) 调配一个新的 Thread 对象。
  • Thread(Runnable target, String name) 调配一个新的 Thread 对象。

– Runnable 接口创立多线程和继承 Thread 类创立多线程的区别:

  • 类只能单继承,实现 Runnable 还能够继承其余的类
  • Runnable 设置线程工作和开启线程拆散。

匿名外部类的形式实现线程的创立

@Test
    public void testThread(){new Thread("线程一"){
            @Override
            public void run() {for (int i = 0; i < 5; i++) {System.out.println(getName()+i);
                }
            }
        }.start();}
    @Test
    public void testRunnable(){new Thread( new Runnable(){
            @Override
            public void run() {System.out.println("匿名线程");
            }
        }).start();}

线程平安问题:

  • 多线程拜访了共享的数据就会产生线程平安问题;(多线程操作了同一批数据)
public class TicketThead extends Thread{public static void saleTicket(String ThreadName){for (int i = 10; i > 0 ; i--){System.out.println(ThreadName+"_"+ i);
        }
    }
    @Test
   public void testTicketThrea(){TicketThead ticketThead = new TicketThead();
        new Thread("线程 1"){
            @Override
            public void run() {String name = getName();
                ticketThead.saleTicket(name);
            }
        }.start();
        new Thread("线程 2"){
            @Override
            public void run() {ticketThead.saleTicket(getName());
            }
        }.start();
        new Thread("线程 3"){
            @Override
            public void run() {ticketThead.saleTicket(getName());
            }
        }.start();}
}

多线程平安问题的原理剖析:

4.2 线程同步技术解决线程平安问题

  1. 同步代码块
 格局:synchronized(锁对象){可能呈现线程平安问题的代码(拜访了共享数据的代码)}
  • 锁对象能够为任意的对象(个别为共享资源的对象),定义的锁对象个别放在 run 办法之外,同步代码块放在 run 办法体内。
  • 锁对象作用:把同步代码块锁住,只让一个线程在同步代码块中执行,线程没有执行结束,不会开释锁
 private int ticket = 100;
        Object obj = new Object();
        @Override
        public void run() {while (true) {synchronized(obj){if (ticket > 0) {
                        try {Thread.sleep(10);
                        } catch (InterruptedException e) {e.printStackTrace();
                        }
                        System.out.println(Thread.currentThread().getName() + "正在卖第" + ticket--);
                    }
                }
            }
        }

同步代码块的原理

  1. 同步办法
  • 同步办法的锁对象就是以后实现类对象 this
public void run() {while (true) {saleTicket();
            }
        }
private synchronized void saleTicket(){if (ticket > 0) {
        try {Thread.sleep(10);
        } catch (InterruptedException e) {e.printStackTrace();
        }
        System.out.println(Thread.currentThread().getName() + "正在卖第" + ticket--);
    }
}
  • 动态同步代码块的锁对象是以后实现类的 class 文件对象
  private static /*synchronized*/ void saleTicket(){synchronized(Runnable.class){if (ticket > 0) {
                    try {Thread.sleep(10);
                    } catch (InterruptedException e) {e.printStackTrace();
                    }
                    System.out.println(Thread.currentThread().getName() + "正在卖第" + ticket--);
                }
            }
        }

3. 锁机制

  • 接口 Lock –>java.util.concurrent.locks
  • 实现类 java.util.concurrent.locks.ReentrantLock
  • 所有办法 接口办法 形象办法 Modifier and Type Method and Description
  • void lock() 获取锁。
  • void unlock() 开释锁。
  • 应用步骤:在成员地位创立一个 ReentrantLock 对象
public void run() {while (true) {lock.lock();
                if (ticket > 0) {
                    try {Thread.sleep(10);
                        System.out.println(Thread.currentThread().getName() + "正在卖第" + ticket--);
                    } catch (InterruptedException e) {e.printStackTrace();
                    }finally {lock.unlock();
                    }
                }
            }
        }

线程的状态

期待唤醒(线程之间的通信)

  • 期待状态,一个正在无限期期待另一个线程执行一个特地唤醒动作的线程处于这一状态。
  • Object 类中的办法:
  • wait 和 notify 办法必须要在同步代码块或者同步办法中应用,因俄日锁对象必须是同一个
  • void wait() 使以后线程期待另一个线程调用此对象的办法或 notify() notifyAll() 办法。
  • void wait(long timeout) // 在指定工夫内没有被唤醒,会主动醒过来
  • 使以后线程期待另一个线程调用此对象的办法或 notify() notifyAll() 办法,或一个指定的工夫流逝。
  • void notify() 唤醒一个在这个对象的监视器上期待的单个线程。
  • void notifyAll() 唤醒正在期待此对象监视器上的所有线程。
public static void main(String[] args) {Object obj = new Object();
        new Thread("顾客线程"){
            @Override
            public void run() {synchronized (obj){System.out.println(getName()+"告知老板要买的包子数量和品种!");
                    try {obj.wait();  // 开释了锁对象
                    } catch (InterruptedException e) {e.printStackTrace();
                    }
                    System.out.println("开吃包子咯");
                }
            }
        }.start();
        new Thread("老板线程"){
            @Override
            public void run() {synchronized (obj){
                    try {Thread.sleep(5000);
                    } catch (InterruptedException e) {e.printStackTrace();
                    }
                    System.out.println(getName()+"告知顾客包子做好了");
                    obj.notify();}
            }
        }.start();}

期待唤醒机制(线程间的通信)

  • 就是一个线程执行完规定的操作之后就进入期待状态(调用 wait()), 期待其余线程实现他们指定的代码后再将其唤醒(notify)wait/notify 就是线程间的一种合作机制
  • 多个线程在解决同一个资源,然而解决的动作(线程的工作)不一样
  • 多个线程并发执行时,默认状况下 CPU 是随机切换线程的,当咱们须要多个线程共同完成一件工作,心愿他们能法则的执行,多线程之间须要协调通信,以此达到多线程独特操作一份数据
// 线程一
public class BaoZiPu extends Thread{
    private BaoZi bz;

    public BaoZiPu(BaoZi bz) {this.bz = bz;}
    @Override
    public void run() {synchronized (bz){if (bz.flag == true){
                try {bz.wait();
                } catch (InterruptedException e) {e.printStackTrace();
                }
            }
            if (bz.flag == false){
                bz.name = "叉烧包";
                System.out.println(getName() + ":" + "开始生产"+bz.name+"包子");
                try {Thread.sleep(5000);
                } catch (InterruptedException e) {e.printStackTrace();
                }
                System.out.println("生产好了包子");
                bz.flag = true;
                bz.notify();}
        }
    }
// 线程二
public class Consumer extends Thread {
    private BaoZi bz;

    public Consumer(BaoZi bz) {this.bz = bz;}

    @Override
    public void run() {synchronized (bz){if (bz.flag == false){
                try {bz.wait();
                } catch (InterruptedException e) {e.printStackTrace();
                }
            }
            if (bz.flag == true){System.out.println( getName() + ":" + "开吃" + bz.name + "包子!");
                try {Thread.sleep(5000);
                } catch (InterruptedException e) {e.printStackTrace();
                }
                System.out.println("包子吃完了!");
                bz.notify();
                bz.flag = false;
            }
        }
    }
}
//
 BaoZi bz = new BaoZi();// 传入的锁对象是同一个
new BaoZiPu(bz).start();
new Consumer(bz).start();

线程池:

  • 频繁的创立线程和销毁线程须要耗费工夫
  • 其实就是一个包容多个线程的容器,线程池中的线程是能够重复应用的。
  • java.util.concurrent.Executors
  • static ExecutorService newFixedThreadPool(int nThreads) 创立一个线程池,应用固定数量的线程操作了共享无界队列。
  • Future<?> submit(Runnable task) 提交执行一个 Runnable 工作并返回一个示意该工作的将来。
  • void shutdown() 启动一个有序的关机,在以前提交的工作被执行,但没有新的工作将被承受。
ExecutorService executorService = Executors.newFixedThreadPool(2);
executorService.submit(new RunnableThead());

最初

感激你看到这里,文章有什么有余还请斧正,感觉文章对你有帮忙的话记得给我点个赞,每天都会分享 java 相干技术文章或行业资讯,欢送大家关注和转发文章!

正文完
 0