黑马程序员技术交流社区

标题: 为什么多线程不好控制 [打印本页]

作者: 我是刘通    时间: 2015-10-16 19:41
标题: 为什么多线程不好控制
概述
进程:一个正在执行中的程序,每一个进程执行都有一个执行的顺序,该顺序是一个执行路径,或者叫一个控制单元
线程:是进程中一个独立的控制单元,线程在控制着进程的执行
一个进程中至少有一个线程。
Java VM 启动的时候会有一个进程java.exe
该进程中至少有一个线程负责java程序的执行,而且这个线程运行的代码存在于main方法中,该线程称之为主线程。
扩展:其实更细节说明jvm,jvm启动不止一个线程,还有负责垃圾回收机制的线程。
创建线程
如何在自定义的代码中自定义一个线程呢?
创建线程的第一种方式:继承Thread类。
发现运行结果每次都不同,因为多个线程都获取CPU的执行权。cpu执行到谁,谁就执行。
明确一点,在某一时刻,只能有一个程序在运行(多核除外)
cpu在做着快速的切换,以达到看上去是同时运行的效果。
我们可以形象地把多线程的运行形容为在互相抢夺cpu的执行权。
这就是多线程的一个特性:随机性。谁抢到,谁执行。至于执行多长时间,cpu说了算。  
1.        /*
2.        小练习
3.        创建两线程,和主线程交替运行。
4.        */  
5.          
6.        //创建线程Test  
7.        class Test extends Thread  
8.        {  
9.        //  private String name;  
10.            Test(String name)//通过构造函数参数指定线程名称  
11.            {  
12.                super(name);  
13.        //      this.name=name;  
14.            }  
15.            //复写run方法  
16.            public void run()  
17.            {  
18.                for(int x=0;x<60;x++)  
19.                     System.out.println(Thread.currentThread().getName()+"..run..."+x);  
20.        //      System.out.println(this.getName()+"..run..."+x);  
21.            }  
22.        }  
23.          
24.        class  ThreadTest  
25.        {  
26.            public static void main(String[] args)   
27.            {  
28.                new Test("one+++").start();//开启一个线程  
29.                new Test("tow———").start();//开启第二线程  
30.                //主线程执行的代码,一定要放在创建线程语句后面,否则会先执行主线程  
31.                for(int x=0;x<170;x++)  
32.                System.out.println("Hello World!");  
33.            }  
34.        }  
创建线程的第二种方式:实现Runnable接口
     需求:简单的卖票程序。
          多个窗口卖票。 */
1.        class Ticket implements Runnable  
2.        {  
3.            private  int tick = 100;  
4.            public void run()  
5.            {  
6.                while(true)  
7.                {  
8.                    if(tick>0)  
9.                    {  
10.                        //显示线程名及余票数  
11.                        System.out.println(Thread.currentThread().getName()+"....sale : "+ tick--);  
12.                    }  
13.                }  
14.            }  
15.        }  
16.          
17.        class  TicketDemo  
18.        {  
19.            public static void main(String[] args)   
20.            {  
21.                //创建Runnable接口子类的实例对象  
22.                Ticket t = new Ticket();  
23.          
24.                //有多个窗口在同时卖票,这里用四个线程表示  
25.                Thread t1 = new Thread(t);//创建了一个线程  
26.                Thread t2 = new Thread(t);  
27.                Thread t3 = new Thread(t);  
28.                Thread t4 = new Thread(t);  
29.          
30.                t1.start();//启动线程  
31.                t2.start();  
32.                t3.start();  
33.                t4.start();  
34.            }  
35.        }  
实现方式和继承方式的区别
实现方式好处:避免了单继承的局限性
在定义线程时,建议使用实现方式
两种方式的区别:
继承Thread:线程代码存放在Thread子类run方法中
实现Runnable:线程代码存放在接口的子类的run方法中
线程运行状态

状态说明:
•        被创建:等待启动,调用start启动。
•        运行状态:具有执行资格和执行权。
•        临时状态(阻塞):有执行资格,但是没有执行权。
•        冻结状态:遇到sleep(time)方法和wait( )方法时,失去执行资格和执行权,sleep方法时间到或者调用notify( )方法时,获得执行资格,变为临时状态。
•        消忙状态:stop( )方法,或者run方法结束。
注:当已经从创建状态到了运行状态,再次调用start( )方法时,就失去意义了,java运行时会提示线程状态异常。
获取线程名称以及对象
原来线程都有自己默认的名称:Thread-编号 该编号从0开始,通过getName();获取。
Thread类中的方法
static Thread currentThread();获取当前线程对象,和this一样,但更通用
getName():获取线程名称
设置线程名称:setName或者构造函数
注意:局部的变量在每一个线程栈内存区域中都有一份
多线程的安全问题
原因:当多条语句在操作同一个线程共享数据时,一个线程对多条语句只执行了一部分,还没有执行完,另一个线程参与进来执行,导致共享数据的错误。
解决办法:对多条操作共享数据的语句,只能让一个线程都执行完。在执行过程中,其他线程不可以参与执行
同步代码块







欢迎光临 黑马程序员技术交流社区 (http://bbs.itheima.com/) 黑马程序员IT技术论坛 X3.2