首页 > 编程语言 > 详细

多线程

时间:2020-06-29 14:50:25      阅读:49      评论:0      收藏:0      [点我收藏+]

多线程概述

日常生活中很多事都是可以同时进行的,例如:人可以同时进行呼吸、血液循环、思考问题等活动。

多线程是指一个应用程序中有多条并发执行的线索,每条线索都被称作为一个线程,它们会交替执行,彼此之间可以进行通信。

 

多线程之主线程概念:JVM启动后,会有一个执行路径(线程)从main方法开始的,一直执行到main方法结束,这个线程在Java中称之为主线程。

 

 

线程对象调用 run方法和调用start方法区别?

 调用run方法不开启线程。仅是对象调用方法。

 调用start开启线程,并让jvm调用run方法在开启的线程中执行。

 

 

Thread

 

创建线程

    方式一继承Thread

 

创建线程的步骤

 

  1. 定义一个类继承Thread类。
  2. 重写run方法。
  3. 创建子类对象

调用start方法,开启线程并让线程执行,同时还会告诉JVM去调用run方法。


public class Demo {
    public static void main(String[] args) {
        //创建自定义线程对象
        MyThread myThread = new MyThread();
        //开启新线程    
        myThread.start();
        while (true) {// 死循环
            System.out.println("Main 方法在运行");
        }
    }
}

 

方式二 实现Runnable接口

  1. 定义类实现Runnable接口
  2. 覆盖接口中的run方法
  3. 创建Thread类的对象
  4. Runnable接口的子类对象作为参数传递给Thread类的构造函数
  5. 调用Thread类的start方法开启线程

 

方式三实现callable接口:此方法不常用就不做探究了,还有别的开启线程的方法,我最常用的是上面俩种。

 

线程安全问题

个人理解:线程安全就是说多线程访问同一代码,不会产生不确定的结果,而不安全就是多个线程对同一个对象进行操作,对象本身会产生不确定的结果。

举个例子:你去食堂打饭(你是一个线程),你来晚了,就剩最后一份糖醋排骨了(不纠结喜不喜欢吃的问题)你正在向阿姨要最后一份排骨,这时候另外一个人(另外一个线程)过来插你队也要糖醋排骨。这时候阿姨按理来说应该把排骨给你,可是这个插你队的是阿姨侄子,阿姨可以给你也可以给他侄子(就看公私分不分明)。这样阿姨就处在不确定的情况下。而线程安全就是直接强行规定死了,只能你这个线程打完饭,后面的人才能去打饭,只有等你释放了食堂阿姨这个资源之后下面的人才能去进行(打饭)操作。你不打完饭释放资源,下面的不可能去操作食堂阿姨这个角色。(个人理解有问题欢迎━(*`∀´*)ノ亻!指正)

不喜欢吃糖醋排骨我再来一个:买票

多线程模拟火车站的售票窗口,每一个线程表示一个售票窗口,共出售100张票

技术分享图片
ublic class Demo2 {
    public static void main(String[] args) {
        TicketWindow window = new TicketWindow();
        new Thread(window,"窗口1").start();
        new Thread(window,"窗口2").start();
        new Thread(window,"窗口3").start();
        new Thread(window,"窗口4").start();
    }
}
class TicketWindow implements Runnable{
    private int tickets = 100;
    @Override
    public void run() {
        while(true){
            if(tickets > 0){
                try {
                    //睡眠让问题更容易“暴露”
                    Thread.sleep(1);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                String threadName = Thread.currentThread().getName();
                System.out.println(threadName + "正在发售第"+tickets--+"张票");
            }else{
                break;
            }
        }
    }
}
View Code

 

上面的例子,由于多个线程共用了同一个资源(票),会造成线程安全问题,票售出了-1张

 

错误截图

技术分享图片

 

 

线程安全问题都是由全局变量静态变量以及共享的变量引起的。若每个线程中对全局变量、静态变量以及共享的变量只有读操作,那么这个全局变量是线程安全的;

若有多个线程同时执行写操作(修改),都需要考虑线程同步,否则就可能发生线程安全问题。

 

 

Java中提供了线程同步机制,它能够解决上述的线程安全问题。

方式一:同步代码块 

方式二:同步方法

同步代码块: 在代码块声明上,加上synchronized

synchronized (锁对象(lock、被锁对象)) {
    可能会产生线程安全问题的代码
}

同步代码块中的锁对象可以是任意的对象;但多个线程时,要使用同一个锁对象才能够保证线程安全。

 lock 是一个锁对象,是同步代码块的关键,锁对象可以是任意类型的对象,是多个线程共享的锁对必须是唯一的,“任意”说的是共享锁对象的类型。所以,锁对象的创建代码不能放到run()方法中,否则每个线程都会创建一个新的对象,每个锁都有自己的标志,那就没有意义了

被锁对象:表示如果当前线程访问"被锁对象"synchronized的代码块时,其它线程不能访问此代码块,另外,也不能访问"被锁对象"中的其它synchronized的代码块;

同步的好处:解决了多线程并发访问的问题,使多线程并发访问的共享数据能够保持一致性

同步的弊端:使当前的对象的工作效率降低;因为要处理线程同步的问题;

 

 

 

同步方法:在方法声明上加上synchronized

public synchronized void method(){
       可能会产生线程安全问题的代码
}


同步方法的也是一样锁住同步的代码,但是锁对象的是Runable实现类对象,也就是this,谁调用方法,就是谁,在这里就是创建的run对象

静态的同步方法,添加一个静态static修饰符,此时锁对象就不是this了,静态同步方法的锁对象是本类的class属性,class文件对象(反射)

               

多线程

原文:https://www.cnblogs.com/cmm123/p/13207727.html

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!