Java基础视频笔记(八):多线程编程

多线程编程:

1、进程与线程

线程:程序中单独顺序的控制流;
线程本身依靠程序进行运行;
线程是程序中的顺序控制流,只能使用分配给程序的资源和环境。
进程:正在执行的程序;
一个进程可以包含多个线程;
一个进程至少要包含一个线程
单线程:程序中只存在一个线程,实际上,主方法就是一个主线程;

多线程:多线程是在一个程序中运行多个任务;

多线程的目的:更好的使用CPU的资源;

2、线程的实现

两种方式:1、继承Thread类
 2、实现Runnable接口

Thread类是在java.lang包中定义的,继承Thread类必须重写 run() 方法;


创建线程:继承于Thread

 

  1. public class MyThread extends Thread {  
  2.     private String name;  
  3.   
  4.     //构造器 传参  
  5.     public MyThread(String name) {  
  6.         // 获取传入 MyThread 方法的字符串  
  7.         this.name = name;  
  8.     }  
  9.       
  10.     public void run() {  
  11.         // 打印  name 的同事,打印 J 的数值  
  12.         for (int j = 0; j < 20; j++) {  
  13.             System.out.println(name + ":" +j);            
  14.         }  
  15.         super.run();  
  16.     }  
  17. }  
  18.  


线程的调用:

 

 

  1. public class ThreadDemo01 {  
  2.   
  3.     public static void main(String[] args) {  
  4.         // 调用 MyThread 类,启动线程  
  5.           
  6.         MyThread mt1 = new MyThread("A");  
  7.         MyThread mt2 = new MyThread("B");  
  8.         /*mt1.run(); 
  9.         mt2.run();*/  
  10.           
  11.         mt1.start();  
  12.         mt2.start();  
  13.     }  
  14.   
  15. }

 


1、进程与线程


进程:正在执行的程序;

每个进程执行,都有一个执行顺序,该顺序是一个执行路径,或者叫一个控制单元

* 一个进程可以包含多个线程;


* 一个进程至少要包含一个线程

线程:程序中单独顺序的控制流;是进程中独立的控制单元;

* 线程本身依靠程序进行运行;

* 线程是程序中的顺序控制流,只能使用分配给程序的资源和环境。

单线程:程序中只存在一个线程,实际上,主方法就是一个主线程;

多线程:多线程是在一个程序中运行多个任务;

多线程的目的:是更好的使用CPU的资源;


JavaVM 启动的时候会有一个进程java.exe;

该进程中至少一个线程负责Java程序的执行,

而且这个线程运行的代码存在于main方法中,该线程称之为主线程;

扩展:JVM启动不止一个线程,除了执行主函数代码,还有一条路径负责垃圾回收机制的线程;

        有多条执行路径,称为多线程。

多线程存在的意义:

多条代码同时执行,提高效率;

2、线程的实现:自定义线程控制单元

通过API的查找,Java已经提供了对这类事物的描述:
java.lang 包 Thread:程序中的执行线程;

两种方式:1、继承Thread类
 2、实现Runnable接口

Thread类是在java.lang包中定义的,继承Thread类必须重写 run() 方法;

/ThreadDemo/ThreadDemo01.java

class Demo extends Thread{
public void run(){// 重写run方法
System.out.println("demo run");
}
}

class ThreadDemo{
public static void main(String[] args){
// 建立好一个对象
Demo d = new Demo(); // 就是创建好一个线程
d.start(); // 使进程开始执行
  // start调用run()方法
}
}

  



发现运行结果每一次都不同;

因为多个线程都在获取CPU的执行权,CPU执行到谁,谁就运行;

明确一点,在某一时刻,只能有一个程序在运行,多核除外;

CPU 其实是在 快速的切换,以达到看上去是同时运行的效果;

我们可以形象的把多线程的运行,形容为在互相抢夺CPU的执行权;

这就是多线程的一个特性:随机性。 谁抢到谁执行,至于执行多长时间,是CPU说了算;

为什么要覆盖 run() 方法?


Thread类用于描述线程:

该类定义了一个功能,用于存储线程要运行的代码,该存储功能就是run()方法;

run() 就是存储线程要运行的代码。

如果直接调用run()方法,只会被主线程单一执行,没有第二条执行路径,因为没调用start()启动线程控制单
元。
d.run(); 仅仅是对象调用方法,线程虽然创建了,但是没有开启
d.start(); 开启线程并执行该线程的run方法


3、线程的状态:

sleep(time); // 时间一到,自然醒来
wait(); // 不能自动恢复
notify; // 主动唤醒wait()
stop(); // 停止线程

阻塞状态:临时状态,具备执行资格,但没有执行权;
冻结状态:放弃了执行资格;
 * 唤醒时,先回到临时状态,获取执行资格;


4、线程标识(线程名称)

调用父类的私有对象 name 两种方法:

1、getName();
2、super(name);

4、线程的常用方法


currentThread();  获取当前线程对象
getName(); 获取线程的名称
  设置线程名称:setName 或者 构造函数

* 局部变量,在每一个线程区域中都有独立的一份地址;
   int x = 0; 所指的内存地址是不同的;

* 全局变量  private static int ticket = 100; // 多个线程共用一个变量
示例:卖票 TichetDemo.java
如果定义静态,变量的生命周期较长,占用CPU 资源较多
要实现Runnable接口解决:

创建线程的第二种方式:实现 Runnable 接口

步骤:  1、定义类实现Runnable接口
2、覆盖Runnable接口的run方法
3、通过Thread建立线程对象
4、将Runnable接口的子类对象作为实际参数传递给Thread类的构造函数
5、调用Thread累的start方法开启线程并调用RUN你爸了本来、接口子类的run方法

      ¥¥经常考:实现接口和继承类的区别是什么?

* 继承只能继承一次,当一个类已经继承了一个父类,此时就不能再继承Thread;

 此时就需要通过实现Runnable接口,调用线程执行代码;

* 实现的好处,就是避免了单继承的局限性; 在定义线程时,建议使用实现方式、
 
* 区别:存放代码位置不同

 继承Thread:线程代码存放Thread子类run方法中;

 实现Runnable:线程代码存在接口的子类的run方法中;

接口的方法不能抛出异常,否则报错,只能try catch;
try{Thread.sleep(10);}catch{Exception e};

* 通过分析发现:打印出 0, -1, -2 等错票;

* 多线程的运行,最担心出现安全问题;

问题原因:

* 当多条语句在操作同一个线程共享数据时,一个线程对多条语句只执行了一部分,还没有执行完;
 导致共享数据的错误;

= = =
Java对于多线程的安全问题提供了专业的解决方法:

同步代码块;

synchronized(对象){

需要被同步的代码
}

()里的对象就是“锁”;

“同步代码块”相当于“上了锁”,使用的时候,其他线程就无法执行这块代码;

同步的前提:
1、必须要有两个或者两个以上的线程;
2、必须是多个线程使用同一个锁
3、必须保证同步中只能有一个线程在运行

同步的好处:解决多线程的安全问题

同步的弊端:多个线程都要判断是否有“锁”,消耗资源,变得稍慢;

如何找问题:1、明确哪些代码是多线程与运行代码~
    2、明确共享数据;
    3、明确多线程运行代码中哪些语句是操作共享数据的;

同步的两种方法:1、同步代码块;2、同步方法

posted @ 2007-07-09 22:35  蒋至乙  阅读(190)  评论(0编辑  收藏  举报