黑马程序员——java多线程

——- android培训java培训、期待与您交流! ———-

什么是进程?
Ctrl+Shift+Esc  打开windows任务管理器
进程是操作系统动态执行和资源分配的一个基本单元,就是程序执行的过程,在这个过程中会占用内存空间和CPU资源。在操作系统中,程序的体现就是进程。

一个程序至少有一个进程,一个复杂的应用程序可能启动并使用多个进程,例如谷歌Chrome浏览器、腾讯的QQ等采用的就是多进程架构设计。

进程间相互独立,不能互相访问或共享资源

相关性,看你CPU的核心有几个(双核处理器、四核处理器、八核处理器)

线程是比进程更小的能独立运行的基本单位,它是进程的一部分


一个进程可以拥有多个线程,但至少要有一个线程,即主执行线程(java的main方法),我们之前写的都是单线程程序。


线程不能够单独执行,它必须运行在处于活动状态的进程中,它可与同属一个进程的其他线程共享进程所拥有的全部资源


生活案例:
1. 火车可以拥有多节车厢,但至少要有一节车厢,火车就是进程,每个
    车厢就是一个线程
2. QQ可以打开多个聊天窗口,QQ就是进程,每个聊天窗口就是一个线
     程

在一个程序中能让两个for循环同时执行吗?一个进程中的多个线程可以并发(同时)执行,因此用多线程编程即可解决这个问题。

有必要搞多个线程吗?有什么用?多线程编程能解决什么问题?

在一些执行时间长、需要等待的任务上(文件读写和网络传输等),多线程就比较有用了。

例如:多图片上传
方案1:一张一张来
方案2:多张同时开始(多线程编程)

多线程是为了共享内存、充分利用CPU,是为了同时完成多项任务,是为了提高资源(内存和CPU)使用率从而提高程序的执行效率。

一个(程序)进程中如果只有一条生产线,这个程序称为单线程。
一个(程序)进程中如果有多条生产线,这个程序称为多线程。
class Demo extends Thread {    //生产线 (线程类)

    public void run(){
        for(int x=30; x<50; x++){
                 System.out.println("Thread----"+x);
        }
    }
}
class  ThreadDemo {

    public static void main(String[] args) {    //主线程(必须有的)

        Demo d1 = new Demo();   //创建一个生产线(线程)
        d1.start();   //启动线程
        for(int x=0; x<30; x++){     
                System.out.println("main----"+x);
        }
    }
}
C++这种语言传统上一直是性能之王。但是,C++对多线程技术的支持非常有限。标准C++甚至没有提到线程这个概念。要想使用C++开发多线程程序是非常困难的。

Java从一开始就在语言层面上支持多线程。使用Java编写多线程的程序是非常简单的。因此,基本上所有的Java程序,包括J2ME、J2SE、J2EE程序都支持多线程技术。在传统单核、单进程CPU上,Java多线程程序在性能上无法与C++单进程程序相比。但是,随着多核、超线程CPU时代的到来,将成就Java性能之王的地位!

Java中有两类线程:User Thread(用户线程)、Daemon Thread(守护线程或后台服务线程) 。守护线程的作用是为其他线程的运行提供服务,比如说GC线程。

在Java中实现多线程有两种方式:
方式一. 继承Thread类
方式二. 实现Runnable接口

方式一:

java.lang.Thread是Java提供的线程类,我们通常可以借助于它来实现多线程编程。
实现步骤:
自定义线程类即生产线(继承Thread类)
重写Thread类中的run()方法,把希望能同时运行的代码放在run()方法中。
创建生产线,即创建线程类的对象并调用start()方法启动生产线

该类常用方法:
public long getId(),获得该线程的标识符(线程 ID) ,它在创建该线程时生成。线程 ID 是唯一的,并终生不变。
public final void setName(String name),给线程命名,不命名的话都有默认的,格式为:Thread-0、Thread-1...
public final String getName(),获得线程的名字
public void start(),使该线程开始执行,JVM会自动调用该线程的 run() 方法。
public static void sleep(long millis),让线程休眠(暂停)多少毫秒
public static Thread currentThread(),获得当前正在执行的线程对象的引用。(方式二会用到)

多线程执行流程:

每个Java程序都有一个默认的主线程。Java程序总是从主类的main方法开始执行。当JVM加载代码,发现main方法后就启动一个线程,这个线程就称作"主线程",该线程负责执行main方法。在main方法中再创建的线程就是其他线程。


如果main方法中没有创建其他线程,那么当main方法执行完时JVM就会结束Java应用程序。但如果main方法中创建了其他线程,那么JVM就要在主线程和其他线程之间轮流切换,保证每个线程都有机会使用CPU资源,即使main方法结束(主线程结束)JVM也不会结束,要一直等到该程序所有线程全部结束才结束Java程序

方式二:

java.lang.Runnable接口是Java提供的实现多线程编程的另一种方式,该接口只定义了一个
无参的run方法。

具体实现步骤:
创建假线程类即假生产线,覆盖Runnable接口中的run方法,把希望能同时运行的代码放在run()方法中。
创建生产线,即通过Thread类创建一个线程(构造方法需要一个线程类对象)。
启动生产线,即调用Thread类对象的start方法开启线程。
class Shengchanxian implements Runnable {   //创建线程类(不是真正的生产线)
    public void run(){
        for(int j=0; j<30; j++){
              System.out.println(Thread.currentThread().getName()+"-"+j);
        }
    }
}
class Demo{
    public static void main(String[] args) {   //主线程
        Shengchanxian scx=new Shengchanxian();

        Thread t1=new Thread(scx);  //创建第一个生产线
        t1.start();    //启动

        Thread t2=new Thread(scx);  //创建第二个生产线
        t2.start();   //启动
    }
}

线程安全问题:

模拟实现:除夕那天北京到郑州的动车票只剩下10张,两个窗口同时在卖

public class SaleWindow implements Runnable {

              private int ticket = 10;      // 车票编号,共享资源

              public void run() {
          for (int i = 1; i <= 10; i++) {      // 卖票
                      if (ticket >= 1) {
                                           System.out.println(Thread.currentThread().getName() 
                                           + "卖编号"+ ticket + "票");
                                           ticket - -;
                  Thread.sleep(500);   // 模拟卖票速度,半秒一张
                                   }
                      }
           }
           public static void main(String[] args) {
        SaleWindow sw = new SaleWindow();
        new Thread(sw).start();     // 窗口1
        new Thread(sw).start();    // 窗口2
           }
}

解决线程安全问题:

出现线程安全问题的主要原因是:线程之间是独立的,多个线程之间共享的数据不同步

判断多线程程序是否存在安全隐患:
1. 代码中存在共享数据
2. 多个线程可能同时操作共享数据

解决线程安全问题的办法:java中提供了一个同步机制(锁)。即让操作共享数据的代码在某一时间段,只被一个线程执行(锁住),在执行过程中,其他线程不可以参与进来,这样共享数据就能同步了。简单来 说,就是给代码加把锁。

Java同步机制的实现方式:
同步代码块
同步方法(函数)

死锁问题:

虽然同步锁机制解决了线程安全问题,但是也带来一些弊端:

    1. 效率会降低,每次都需要判断锁
    2. 可能引发死锁(彼此占用所需要的资源),出现的概率非常小,非常特殊

线程之间彼此占用对方所需的资源,就是死锁

解决死锁问题:

该放手时要放手,之前是等到当前线程执行完时才释放锁,现在必须更及时的人工去释放锁(开锁)

因为任何对象都有锁,所以Object类提供了释放锁的方法:
public final void wait(),让当前线程等待,同时释放锁,直到被再次唤醒
public final void wait(long timeout),在指定时间内让当前线程等待,同时释放锁

notify方法:

wait()和sleep()都可以让当前线程等待,区别:
    1,sleep():释放执行权(等待),不释放锁
    2,wait():释放执行权(等待),同时释放锁

如果调用的是无参的wait()方法,那锁就一直释放,当前线程一直等待,还需要唤醒。Object类提供了notify()方法用来唤醒某个被wait()的锁,也就是唤醒线程

细节:
wait()和notify()方法都是操作锁的,而锁存在于同步中,也就是说这两个方法必须出现在同步中(同步代码块或同步方法)。同步锁不仅可以解决昨天的线程安全问题,还可以实现线程间的通信

单例设计模式(singleton):

单例即只有一个实例,该模式的作用是保证程序中某个类的对象只有一个。

一些窗口就设计成了单例设计模式,例如“任务管理器”

实际应用:将来的数据库连接类(就业班)

怎么实现?
1. 构造方法私有化,不让new
2. 提供一个公有静态方法返回一个实例

懒汉式的线程安全:

//懒汉式
class Single{
    private static Single s = null;
    private Single(){}
    public static Single getInstance(){
        if (s == null){
               s = new Single();
        }
        return s;
    }
}

饿汉式:

//饿汉式
public class Singleton{
            private static Singleton s = new Singleton ();
            private Singleton (){}
            public static Singleton getInstance(){return s;}
 } 

——- android培训java培训、期待与您交流! ———-

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值