• 多线程讲解和作业


    多线程:

    多线程的原理:

    原理:多线程执行时候,在栈内存中,其实每一个执行线程都有一片所属的栈内存的空间,进行方法的压栈,和弹栈.
     
    原理图:

    多线程的创建:

    三种方式:

    第一种继承:

     1 package com.heima.duoxiancheng;
     2 
     3 //多线程的继承方式创建
     4 public class Demo01 extends Thread {
     5     //利用继承的特点
     6     //将线程名称传递进行设置
     7     public Demo01(String name) {
     8         super(name);
     9     }
    10 
    11     //重写run方法
    12     @Override
    13     public void run() {
    14         for (int i = 0; i < 5; i++) {
    15             //getName()方法来自与父亲类Thread
    16             System.out.println(getName() + "正在执行:" + i);
    17         }
    18     }
    19 
    20     public static void main(String[] args) {
    21         //创建类对象
    22         Demo01 a = new Demo01("德玛");
    23         //创建线程对象
    24         Thread B = new Thread(a);
    25         //开启线程
    26         B.start();
    27         //在主线程种执行
    28         for (int j = 0; j < 5; j++) {
    29             System.out.println("我叫做:" + j);
    30         }
    31     }
    32 }

     第二种接口:

     1 package com.heima.duoxiancheng;
     2 //接口方式书写多线程
     3 public class Demo02 implements Runnable {
     4     //重写run方法
     5     @Override
     6     public void run() {
     7         for (int i = 0; i < 5; i++) {
     8             System.out.println(Thread.currentThread().getName() + "-" + i);
     9         }
    10     }
    11     public static void main(String[] args) {
    12         //创建实现类对象
    13         Demo02 a=new Demo02();
    14         //创建线程对象
    15         Thread thread = new Thread(a,"剑圣");
    16         //开启线程
    17         thread.start();
    18         for (int j = 0; j < 5; j++) {
    19             System.out.println("我是主线程:"+j);
    20         }
    21 
    22     }
    23 }

    三.匿名内部类方式创建

     1 package com.heima.duoxiancheng;
     2 //匿名内部类
     3 public class Demo03 {
     4     public static void main(String[] args) {
     5         //创建Runnable对象
     6         Runnable runnable = new Runnable() {
     7             //重写run方法
     8             @Override
     9             public void run() {
    10                 //创建多态对象
    11                 for (int i = 0; i < 5; i++) {
    12                     System.out.println("德玛:" + i);
    13                 }
    14             }
    15         };
    16       new Thread(runnable).start();
    17         for (int j = 0; j < 5; j++) {
    18             System.out.println(Thread.currentThread().getName()+" "+j);
    19         }
    20     }
    21 }

    优势:使用线程的匿名内部类方式,可以方便的实现每个线程执行不同的线程任务.

    Thread和Runnable的区别:

    如果一个类继承Thread,则不适合资源共享。但是如果实现了Runable接口的话,则很容易的实现资源共享。

    总结:

    实现Runnable接口比继承Thread类所具有的优势:

    1. 适合多个相同的程序代码的线程去共享同一个资源。

    2. 可以避免java中的单继承的局限性。

    3. 增加程序的健壮性,实现解耦操作,代码可以被多个线程共享,代码和线程独立。

    4. 线程池只能放入实现Runable或Callable类线程,不能直接放入继承Thread的类.

    扩充:在Java种每次程序运行至少启动两个线程,一个是main线程,一个是JVM.

    Thread的构造方法:

     

    • public Thread():分配一个新的线程对象。

    • public Thread(String name):分配一个指定名字的新的线程对象。

    • public Thread(Runnable target):分配一个带有指定目标新的线程对象。

    • public Thread(Runnable target,String name):分配一个带有指定目标新的线程对象并指定名字。

    常用方法:

    public String getName():获取当前线程名称。
    public static Thread currentThread():返回对当前正在执行的线程对象的引用。
    public void start():导致此线程开始执行; Java虚拟机调用此线程的run方法。
    public void run():此线程要执行的任务在此处定义代码。
    public static void sleep(long millis):使当前正在执行的线程以指定的毫秒数暂停(暂时停止执行)。
    注意:如果一个类继承Thread,则不适合资源的共享,但是实现了Runable接口的话,则很容易的实现资源共享.

     


     

    实现Runnable接口比继承Threed类所具有的优势

     

    1.适应多个相同的程序代码的线程去共享一个资源.
    2.可以避免java中的单继承的局限性.
    3.增加程序的健壮性,实现解耦操作,任务可以被多个线程共享,任务和线程独立.
    4.线程池只能放入实现Runnable或Callable类线程,不能直接放入继承Thread的类
    耦合性:类和类之间的相互影响的程度.
    扩充:在java中,每次程序运行至少启动2个线程,一个是main线程,一个是垃圾收集线程,
    因为每当使用Java命令执行一个类的时候,一个是垃圾收集线程,因为每当使用Java执行一个类
    实际东辉启动一个jvm,每个JVM其实都是在操作系统启动一个进程.

     

    线程安全:

    定义:
    如果有多个线程在同时运行,而这些线程可能会同时运行这段代码。程序每次运行结果和单线程运行的结果是一样的,而且其他的变量的值也和预期的是一样的,就是线程安全的。
    实例题目:

     代码演示:

     
     1 package com.heima.duoxiancheng;
     2 //通过接口方式
     3 public class Demo04 implements Runnable{
     4     private int ticket=100;//设置票的个数
     5     Object jock=new Object();
     6     //重写run方法
     7     //执行买票操作
     8     @Override
     9     public void run() {
    10         //窗口永远在开启
    11         while (true){
    12             //使用同步代码块解决去重问题
    13             synchronized (jock){
    14                 if(ticket>0) {//有票可以卖
    15                     try {
    16                         Thread.sleep(100);//模拟出票的时间
    17                     } catch (InterruptedException e) {
    18                         e.printStackTrace();
    19                     }
    20                     //获取当前线程对象的名字
    21                     String name = Thread.currentThread().getName();
    22                     System.out.println(name + "正在卖:" + ticket-- + "张。");
    23                 }
    24             }
    25         }
    26     }
    27 
    28     public static void main(String[] args) {
    29         //创建线程任务的对象
    30         Demo04 thread = new Demo04();
    31         //创建窗口的对象
    32         Thread thread1 = new Thread(thread,"窗口1");
    33         Thread thread2 = new Thread(thread,"窗口2");
    34         Thread thread3 = new Thread(thread,"窗口3");
    35         thread1.start();
    36         thread2.start();
    37         thread3.start();
    38     }
    39 }

     


     

    线程的同步:

    当我们使用多个线程访问同一资源的时候,且多个线程中对资源有写的操作,就容易出现线程安全问题
    解决:
    解决上诉问题多线程访问一个资源安全性问题,也就是解决重复的问题,java中提供了(synchronized)来解决
    线程访问使用三种方式完成同步操作
    1.同步代码快(synchronized)关键字可以用于方法的某个区块中表示区块资源的互斥访问.
    格式:
     
    synchronized(同步锁){
    需要同步操作的代码
    }
    同步锁:
    对象的同步锁只是一个概念,可以想象为在对象上标志记了一个锁
    .锁对象(可以是任意数据对象)
    .多个线程对象,要使用同一把锁.
    注意:在任何时候,最多仍许一个线程拥有同步锁,谁拿到锁就进入代码块,其他的线程只能在外等着(BLDCKED).
    2.同步方法
    3.锁机制

    同步方法:

    同步方法:使用synchronized修饰的方法,就叫做同步方法,保证A线程执行该方法的时候,其他线程只能在方法外等着。
     
    public synchronized void method(){
    可能会产生线程安全问题的代码
    }
    同步锁是谁:
    对于非static方法,同步锁就是this.
    对于static方法,我们使用当前方法所有类的字节代码对象(类名.class)
    代码演示:
     1 package com.heima.biji;
     2 //同步方法
     3 public class Mythread04 implements Runnable{
     4         private int ticket = 100;//定义电影票的个数
     5         //重写run方法
     6         @Override
     7         public void run() {
     8             //每个窗口买票的过程
     9             //窗口永远在开启
    10             while (true){
    11                 sellTicket();
    12             }
    13         }
    14         public synchronized void sellTicket(){
    15             if(ticket>0){
    16                 try {
    17                     Thread.sleep(100);
    18                 } catch (InterruptedException e) {
    19                     e.printStackTrace();
    20                 }
    21                 //获取当前线程对象的名字
    22                 String name = Thread.currentThread().getName();
    23                 System.out.println(name + "正在买:" + ticket-- + "");
    24             }
    25         }
    26     }

    lock锁:

    java.util.concurrent.loks.Lock机制提供了比synchronized代码块,和synchronized方法

    Lock锁也称同步锁,加锁与释放锁方法化了,如下:

    public void lock():加同步锁。
     lock他是一个接口,他只能new 实现类ReentrantLock
    public void unlock():释放同步锁。

    代码快:

     1 package com.heima.biji;
     2 import java.lang.invoke.VarHandle;
     3 import java.util.concurrent.locks.Lock;
     4 import java.util.concurrent.locks.ReentrantLock;
     5 
     6 //Lock锁
     7 public class Mythread05 implements Runnable {
     8     //设置票数
     9     private int ticket = 100;
    10     Lock lock = new ReentrantLock();
    11 
    12     //执行买票操作
    13     @Override
    14     public void run() {
    15         while (true) {
    16             lock.lock();//加同步锁
    17             if (ticket > 0) {//有票可以买
    18                 //每个窗口买票的操作
    19                 //窗口 永远开启
    20                 try {
    21                     Thread.sleep(100);
    22                 } catch (InterruptedException e) {
    23                     e.printStackTrace();
    24                 }
    25                 //获取当前线程对象的名字
    26                 String name = Thread.currentThread().getName();
    27                 System.out.println(name + "正在买:" + ticket-- + "");
    28             }
    29             lock.unlock();//释放同步锁
    30         }
    31     }
    32 }

    线程状态概述:

    当线程被创建并启动后,他既不是一启就进入执行状态,也不是一直处于执行状态:
    在线程生命周期中有6种状态.
     
    线程状态
    导致方式条件
    NEW(新建)
    线程刚被创建,但是并未启动。还没调用start方法。
    Runnable(可运行)
    线程可以在java虚拟机中运行的状态,可能正在运行自己代码,也可能没有,这取决于操作系统处理器。
    Blocked(锁阻塞)
    当一个线程试图获取一个对象锁,而该对象锁被其他的线程持有,则该线程进入Blocked状态;当该线程持有锁时,该线程将变成Runnable状态。
    Waiting(无限等待)
    一个线程在等待另一个线程执行一个(唤醒)动作时,该线程进入Waiting状态。通过wait()方法进入这个状态后是不能自动唤醒的,必须等待另一个线程调用notify或者notifyAll方法才能够唤醒。
    TimedWaiting(计时等待)
    同waiting状态,有几个方法有超时参数,调用他们将进入Timed Waiting状态。这一状态将一直保持到超时期满或者接收到唤醒通知。带有超时参数的常用方法有Thread.sleep 、Object.wait。
       Teminated(被终止)       :        因为run方法正常退出而死亡,或者因为没有捕获的异常终止了run方法而死亡。

    Timed Waiting(计时等待):

    • Timed Waiting在API中的描述为:一个正在限时等待另一个线程执行一个(唤醒)动作的线程处于这一状态。单独的去理解这句话,真是玄之又玄,其实我们在之前的操作中已经接触过这个状态了,在哪里呢?

    BLOCKED(锁阻塞):

    图解:

    Waiting(无限等待):

    图解:

     

  • 相关阅读:
    redis+Keepalived实现Redis主从复制
    Python基础之【第一篇】
    Django之常用命令以及问题汇总
    Django之ORM数据库
    牛掰的python与unix
    Django配置Bootstrap, js
    Django基础教程
    Django安装
    前端学习之jQuery
    centos7安装python3 以及tab补全功能
  • 原文地址:https://www.cnblogs.com/luliang1215/p/10635390.html
Copyright © 2020-2023  润新知