黑马程序员__java基础__多线程
2015-06-15 11:19
375 查看
------Java培训、Android培训、iOS培训、.Net培训、期待与您交流! -------
多线程的描述
一.进程、线程
(1)进程:一个正在执行的程序。每一个进程执行都有一个执行顺序。该顺序是一个执行路径,或者叫一个控制单元。
(2)线程:进程中一个负责程序的控制单元。线程在控制着进程的执行。只要进程中有一个线程在执行,进程就不会结束。
二.多线程
(1)多线程:在java虚拟机启动的时候会有一个java.exe的执行程序,也就是一个进程。该进程中至少有一个线程负责java程序的执行。而且这个线程运行的代码存在于main方法中。该线程称之为主线程。JVM启动除了执行一个主线程,还有负责垃圾回收机制的线程。像种在一个进程中有多个线程执行的方式,就叫做多线程。
(2)多线程的好处:解决了多部分代码同时运行的问题,提高程序执行效率。
多线程的创建
一.继承方式(继承Thread)
(1)步骤:1.
定义一个类继承Thread类。
2. 覆盖Thread类中的run方法。
3. 直接创建Thread的子类对象创建线程。
4. 调用start方法开启线程并调用线程的任务run方法执行。
(2)分析:1. Thread类中的run方法,用于存储线程要运行的代码,所以自定义线程就必须复写run方法。
2.如果线程直接调用run方法,等同于只有一个线程(main)在执行。所以必须要调用start方法才能启动线程。
(3)例子:
<
11d6c
/span>
通过结果可看出:执行是随机、交替执行的。
二.实现方式(实现Runnable)
(1)步骤: 1. 定义类实现Runnable接口。
2. 覆盖接口中的run方法,将线程的任务代码封装到run方法中。
3. 通过Thread类创建线程对象,并将Runnable接口的子类对象作为Thread类的构造函数的参数进行传递。
4. 调用线程对象的start方法开启线程。
(2)分析: 1. 为什么要将Runnable接口的子类对象传递给Thread的构造函数?因为线程的任务都封装在Runnable接口子类对象
的run方法中。所以要在线程对象创建时就必须明确要运行的任务。
2. 实现的方式避免了Java单继承的局限性。所以,创建线程时用实现的方式较为常见。
(3)例子:
线程的安全问题
一.安全问题出现的原因
(1)多个线程在操作共享的数据。
(2)操作共享数据的线程代码有多条。
当一个线程在执行操作共享数据的多条代码过程中,其他线程参与了运算,就会导致线程安全问题的产生。
二.解决办法——同步
(1)同步代码块:格式 synchronized(对象){ 需要被同步的代码;}。其中的对象可以new一个Object对象传进去。
(2)同步函数:格式:在函数上加上synchronized修饰符即可。
(3)同步的前提:1.必须要有两个或者两个以上的线程。2.必须是多个线程使用同一个锁。
(4)同步的利弊:利:解决了多线程的安全问题。弊:多个线程需要判断锁,较为消耗资源。
(5)同步要注意的问题:1.明确哪些代码是多线程运行代码。
2.明确共享数据。
3. 明确多线程运行代码中哪些语句是操作共享数据的。
(6)多线程下的单例模式:
死锁
一.死锁的出现
当同步中嵌套同步时,就有可能出现死锁现象。
二.死锁示例
线程间通信
一.多个线程在处理统一资源,但是任务却不同,这时候就需要线程间通信。
二.等待/唤醒机制涉及的方法:
(1) wait():让线程处于冻结状态,被wait的线程会被存储到线程池中。
(2) notify():唤醒线程池中的一个线程(任何一个都有可能)。
(3) notifyAll():唤醒线程池中的所有线程。
三.wait(),notify(),notifyAll(),用来操作线程为什么定义在了Object类中
(1)这些方法存在与同步中。
(2)使用这些方法时必须要标识所属的同步的锁。同一个锁上wait的线程,只可以被同一个锁上的notify唤醒。
(3)锁可以是任意对象,所以任意对象调用的方法一定定义object类中。
四.wait(),sleep()有什么区别
(1)wait:释放执行权,释放锁。
(2) sleep:释放执行权,不释放锁。
线程的停止
一.让run方法结束
(1)开启多线程运行,运行代码通常是循环结构。只要控制住循环,就可以让run方法结束,也就是线程结束。
(2)run方法中有如下代码,设置一个flag标记。
(1)线程处于了冻结状态,无法读取标记。
(2)Thread类提供该方法interrupt()强制让线程恢复到运行状态中来,这样就可以操作标记让线程结束。
(3)例子:
多线程的描述
一.进程、线程
(1)进程:一个正在执行的程序。每一个进程执行都有一个执行顺序。该顺序是一个执行路径,或者叫一个控制单元。
(2)线程:进程中一个负责程序的控制单元。线程在控制着进程的执行。只要进程中有一个线程在执行,进程就不会结束。
二.多线程
(1)多线程:在java虚拟机启动的时候会有一个java.exe的执行程序,也就是一个进程。该进程中至少有一个线程负责java程序的执行。而且这个线程运行的代码存在于main方法中。该线程称之为主线程。JVM启动除了执行一个主线程,还有负责垃圾回收机制的线程。像种在一个进程中有多个线程执行的方式,就叫做多线程。
(2)多线程的好处:解决了多部分代码同时运行的问题,提高程序执行效率。
多线程的创建
一.继承方式(继承Thread)
(1)步骤:1.
定义一个类继承Thread类。
2. 覆盖Thread类中的run方法。
3. 直接创建Thread的子类对象创建线程。
4. 调用start方法开启线程并调用线程的任务run方法执行。
(2)分析:1. Thread类中的run方法,用于存储线程要运行的代码,所以自定义线程就必须复写run方法。
2.如果线程直接调用run方法,等同于只有一个线程(main)在执行。所以必须要调用start方法才能启动线程。
(3)例子:
<
11d6c
/span>
/** * 创建两个线程,并输出结果 * @author Administrator */ class Test extends Thread//继承thread类 { String name; Test(String name) { this.name=name; } public void run()//复写run方法 { for(int x=0;x<60;x++) { System.out.println(name+"x="+x); } } } public class ThreadTest { public static void main(String[] args) { Test t1=new Test("线程1---");//创建线程 Test t2=new Test("线程2------"); t1.start();//启动线程 t2.start(); for(int x=0;x<60;x++)//main线程 { System.out.println("main线程-"+"x="+x); } } }输出结果为:
通过结果可看出:执行是随机、交替执行的。
二.实现方式(实现Runnable)
(1)步骤: 1. 定义类实现Runnable接口。
2. 覆盖接口中的run方法,将线程的任务代码封装到run方法中。
3. 通过Thread类创建线程对象,并将Runnable接口的子类对象作为Thread类的构造函数的参数进行传递。
4. 调用线程对象的start方法开启线程。
(2)分析: 1. 为什么要将Runnable接口的子类对象传递给Thread的构造函数?因为线程的任务都封装在Runnable接口子类对象
的run方法中。所以要在线程对象创建时就必须明确要运行的任务。
2. 实现的方式避免了Java单继承的局限性。所以,创建线程时用实现的方式较为常见。
(3)例子:
/** * 创建两个线程,并输出结果 * @author Administrator */ class Test implements Runnable//实现Runnable接口 { public void run()//复写run方法 { for(int x=0;x<60;x++) { System.out.println(Thread.currentThread().getName() + "-----" + x); } } } public class ThreadTest { public static void main(String[] args) { Test t=new Test();//创建Runnable子类对象 Thread d1=new Thread(t);//创建线程并把Runnable子类对象作为实际参数传给Thread的构造函数 Thread d2=new Thread(t); d1.start();//启动线程 d2.start(); for(int x=0;x<60;x++)//main线程 { System.out.println("main线程-"+"x="+x); } }输出结果为:
线程的安全问题
一.安全问题出现的原因
(1)多个线程在操作共享的数据。
(2)操作共享数据的线程代码有多条。
当一个线程在执行操作共享数据的多条代码过程中,其他线程参与了运算,就会导致线程安全问题的产生。
二.解决办法——同步
(1)同步代码块:格式 synchronized(对象){ 需要被同步的代码;}。其中的对象可以new一个Object对象传进去。
(2)同步函数:格式:在函数上加上synchronized修饰符即可。
(3)同步的前提:1.必须要有两个或者两个以上的线程。2.必须是多个线程使用同一个锁。
(4)同步的利弊:利:解决了多线程的安全问题。弊:多个线程需要判断锁,较为消耗资源。
(5)同步要注意的问题:1.明确哪些代码是多线程运行代码。
2.明确共享数据。
3. 明确多线程运行代码中哪些语句是操作共享数据的。
(6)多线程下的单例模式:
class Single { private static Single s = null; private Single(){} public static Single getInstance() { if(s ==null) { synchronized(Single.class) { if(s == null) s = new Single(); } } return s ; } }
死锁
一.死锁的出现
当同步中嵌套同步时,就有可能出现死锁现象。
二.死锁示例
/** 写一个死锁程序 */ class LockTest implements Runnable//定义一个类来实现Runnable,并复写run方法 { static Object locka = new Object(); static Object lockb = new Object(); private boolean flag; LockTest(boolean flag) { this.flag=flag; } public void run() { if(flag) { while(true) { synchronized(locka)//a锁 { System.out.println("------if_locka"); synchronized(lockb)//b锁 { System.out.println("------if_lockb"); } } } } else { while(true) { synchronized(lockb)//b锁 { System.out.println("------else_lockb"); synchronized(locka)//a锁 { System.out.println("------else_locka"); } } } } } } public class DeadLock { public static void main(String[] args) { new Thread(new LockTest(true)).start(); new Thread(new LockTest(false)).start(); } }
线程间通信
一.多个线程在处理统一资源,但是任务却不同,这时候就需要线程间通信。
二.等待/唤醒机制涉及的方法:
(1) wait():让线程处于冻结状态,被wait的线程会被存储到线程池中。
(2) notify():唤醒线程池中的一个线程(任何一个都有可能)。
(3) notifyAll():唤醒线程池中的所有线程。
三.wait(),notify(),notifyAll(),用来操作线程为什么定义在了Object类中
(1)这些方法存在与同步中。
(2)使用这些方法时必须要标识所属的同步的锁。同一个锁上wait的线程,只可以被同一个锁上的notify唤醒。
(3)锁可以是任意对象,所以任意对象调用的方法一定定义object类中。
四.wait(),sleep()有什么区别
(1)wait:释放执行权,释放锁。
(2) sleep:释放执行权,不释放锁。
线程的停止
一.让run方法结束
(1)开启多线程运行,运行代码通常是循环结构。只要控制住循环,就可以让run方法结束,也就是线程结束。
(2)run方法中有如下代码,设置一个flag标记。
public void run() { while(flag) { System.out.println(Thread.currentThread().getName()+"....run"); } }二.线程处于冻结状态
(1)线程处于了冻结状态,无法读取标记。
(2)Thread类提供该方法interrupt()强制让线程恢复到运行状态中来,这样就可以操作标记让线程结束。
(3)例子:
class StopThread implements Runnable { private boolean flag =true; public void run() { while(flag) { System.out.println(Thread.currentThread().getName()+"....run"); } } public void changeFlag() { flag = false; } } class StopThreadDemo { public static void main(String[] args) { StopThread st = new StopThread(); <span style="white-space:pre"> </span>Thread t1 = new Thread(st); <span style="white-space:pre"> </span>Thread t2 = new Thread(st); <span style="white-space:pre"> </span>t1.start(); <span style="white-space:pre"> </span>t2.start(); int num = 0; while(true) { if(num++ == 60) { t1.interrupt();//清除冻结状态 t2.interrupt(); st.changeFlag();//改变循环标记 break; } System.out.println(Thread.currentThread().getName()+"......."+num); } System.out.println("over"); } }
相关文章推荐
- 老板的中心是客户,重心是服务,是行业思维;员工的中心是任务,重心是专业,是职业思维;
- 给90后程序员的一个建议
- 程序员如何写出一份好的文档?
- IT 职业规划
- 入行程序员一个月的感受
- 【剑指offer】面试题六:重建二叉树
- 找工作笔试面试那些事儿(5)---构造函数、析构函数和赋值函数
- 找工作笔试面试那些事儿(3)---内存管理那些事
- 找工作笔试面试那些事儿(2)---函数那些事
- 年轻人,你在职场第几层?
- 搜狐面试- Android事件分发机制完全解析,带你从源码的角度彻底理解(下)
- 搜狐面试- Android事件分发机制完全解析,带你从源码的角度彻底理解(上)
- 黑马程序员——Java基础—线程
- 程序员不是砌砖工人,他们是作家
- 黑马程序员——Java基础—java基础语法总结
- 理想的程序员
- 黑马程序员------异常总结
- 程序员的职业素养摘要
- 程序员,为未来准备好了吗?
- 程序员的幸福观