黑马程序员技术交流社区
标题:
为什么多线程不好控制
[打印本页]
作者:
我是刘通
时间:
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