黑马程序员__java基础__多线程

来源:互联网 发布:qq飞车改车吧 软件 编辑:程序博客网 时间:2024/04/30 04:30
------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)例
/** * 创建两个线程,并输出结果 * @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");}}
0 0
原创粉丝点击