线程:
方式一:继承Thread类并且复写run方法.
格式:
class MyThread extends Thread
{
public void run()
{
线程中要运行的代码.
}
}
其步骤为:
1.定义类继承Thread类.
2.复习run方法.---->目的是:用于存储线程中要运行的代码,将自定义的代码存储在run方法中,让线程运行.
3.调用线程的start方法
注意:不是调用run方法.
线程的名字:一般线程有默认的名字,形式为:Thread-编号,编号是从0开始标记的.
也可以获取当前运行线程的名字,用方法:Thread.currentThread().getName()
Thread.currentThread() 是用于获取当前线程的对象.(静态的).
自定义设置线程的名字可以用setName()或者构造函数来设置.
有关线程的继承方式的代码实例和练习:
1 /*
2 线程:步骤:
3 1.定义一个类继承Thread
4 2.复写类中的润方法
5 3.创建一个对象(创建一个对象也就创建了一个线程)
6 4.调用线程的start()方法,调用start方法后,启动了线程,同时也调用了run()方法.
7 */
8 class MyThread extends Thread //第一步
9 {
10 public void run() //第二步
11 {
12 for(int x = 0; x < 60; x++)
13 System.out.println("MyThread run!====="+x);
14 }
15 }
16
17
18 class ThreadDemo
19 {
20 public static void main(String args[])
21 {
22 MyThread mt = new MyThread();//创建了一个线程. //第三步
23 mt.start(); // 开启线程并运行该线程的run方法. //第四步
24 //mt.run(); // 仅仅是对象调用方法,虽然创建了线程,但并未运行线程.
25
26 for(int x = 0; x < 60; x++)
27 System.out.println("Hello World!====="+x);
28 }
29 }
View Code
1 /*
2
3 */
4 class FirstThread extends Thread
5 {
6 //private String name;
7 FirstThread(String name)
8 {
9 //this.name = name;
10 super(name);
11 }
12 public void run()
13 {
14 for(int i = 1; i <= 50; i++)
15 {
16 //System.out.println(this.name+"FirstThread run.====="+i);
17 System.out.println((Thread.currentThread()==this)+"......"+this.getName()+"FirstThread run.====="+i);
18 }
19 }
20 }
21
22 class ThreadTest
23 {
24 public static void main(String args[])
25 {
26 FirstThread ft1 = new FirstThread("First===");
27 FirstThread ft2 = new FirstThread("Second===");
28 ft1.start();
29 ft2.start();
30
31 for(int i = 1; i <= 50; i++)
32 {
33 System.out.println("mainThread run.====="+i);
34 }
35 }
36 }
View Code
1 /*
2 售票窗口例子:
3 多个窗口能够同时卖票.
4 */
5
6 class Ticket extends Thread
7 {
8 private static int ticket = 100; //不用static时候.两个窗口都会同时卖同号的票,即100张票连个窗口都会卖一次(相当于卖了200次)
9 Ticket(String name)
10 {
11 super(name);
12 }
13 public void run()
14 {
15 while(true)
16 {
17 if(ticket>0)
18 {
19 System.out.println(Thread.currentThread().getName()+"===卖票===="+ticket--);
20 }
21 }
22 }
23 }
24
25
26 class TicketDemo
27 {
28 public static void main(String args[])
29 {
30 Ticket t1 = new Ticket("窗口1");
31 Ticket t2 = new Ticket("窗口2");
32 t1.start();
33 t2.start();
34
35 }
36 }
线程的第二种方式:
实现Runnable接口:
格式为:
class MyRunnable implements Runnable
{
public void run()
{
线程中要运行的有关代码.
}
}
其步骤一般为:
1.定义一个类实现Runnable接口.
2.复写Runnable接口中的run方法.
3.通过Thread类来创建一个对象.
4.将Runnable的子类的对象作为实际参数传给Thread类中的构造函数.
5.调用Thread类中的start方法.开启线程,并调用Runnable接口的子类的run方法.(可以理解为run方法又start方法开启调用的)
例如:
class MyRunnable implements Runnable //步骤1
{
public void run() //步骤2
{
S.o.p();
}
}
class RunnableDemo
{
p.s.v.main()
{
MyRunnable mr = new MyRunnable();
Thread t1 = new Thread(mr); //步骤3---4
t1.start(); //步骤5
}
}
1 /*
2 售票窗口例子:
3 多个窗口能够同时卖票.
4 不使用静态的ticket来完成每个窗口的卖票,且不会卖重复的票.
5 通过实现Runnable接口来完成.
6
7 创建线程的第二种方法:
8 实现Runnable接口来完成.
9 步骤:
10 1.定义一个类实现(implements)Runnable接口
11 2.复写Runnable接口中的run方法
12 3.通过Thread类来创建对象
13 4.将Runnable接口的子类对象作为实际参数传给Thread类中的构造函数.
14 5.调用Thread类中的start方法开启线程,并调用Runnable接口的子类的run方法.
15 */
16
17
18 class Ticket implements Runnable
19 {
20 private int ticket = 100; // private static int ticket = 100;
21 /*
22 由于Ticket并未继承Thread,该类并没有getName()的方法,因此是不能调用的.
23 Ticket(String name)
24 {
25 super(name);
26 }
27 */
28 public void run()
29 {
30 while(true)
31 {
32 if(ticket>0)
33 {
34 System.out.println(Thread.currentThread().getName()+"===卖票====="+ticket--);
35 }
36 }
37 }
38 }
39
40
41 class RunnableTicketDemo
42 {
43 public static void main(String args[])
44 {
45 Ticket t = new Ticket(); //t是共享数据.
46
47 /*
48 下面的方法不静态ticket时候会出现卖了200张票的情况,如何不静态 ticket =100,也自定义线程名且不出现卖200张票的情况????
49 */
50 //Ticket tt = new Ticket();
51 //Ticket ttt = new Ticket();
52 //Ticket tttt = new Ticket();
53
54 //Thread t1 = new Thread(t,"窗口1");
55 //Thread t2 = new Thread(tt,"窗口2");
56 //Thread t3 = new Thread(ttt,"窗口3");
57 //Thread t4 = new Thread(tttt,"窗口4");
58 /*
59 下面的代码执行后,Thread.currentThread().getName()获取的是默认的线程名.
60 */
61 Thread t1 = new Thread(t);
62 Thread t2 = new Thread(t);
63 Thread t3 = new Thread(t);
64 Thread t4 = new Thread(t);
65
66 t1.start();
67 t2.start();
68 t3.start();
69 t4.start();
70 }
71 }
View Code
继承方式和实现方式的多态的区别和特点:
实现方式:避免了单继承的局限性.一般定义线程时,建议使用实现方式.
区别:
1.继承Thread:线程代码存放在Thread的子类的run方法中.
2.实现Runnabel:线程的代码存放在Runnable接口的子类的run方法中.
最后是同步代码块,解决了多线程的安全性问题
格式为:
synchronized(对象)
{
需要被同步的代码块.
}
有关实现Runnable接口和同步的示例和练习代码:
1 /*
2 多线程的安全问题;
3 打印出了票数为0.-1.-2等问题.
4
5 问题分析,多条语句同时使用同一线程的共享数据时,一个线程只执行了一部分,还未执行完,另一个线程就参与进来执行了,导致共享数据的错误.
6 在if判断中,当ticket=1时,一个线程进去执行语句后,另一个线程也执行进来.
7 此时的ticket已经通过ticket--变成了0,从而导致了输出票数为0或者负数的情况.
8 解决方案:
9 对操作多条共享数据的语句,让一个线程完全执行完毕后才让另一个线程执行,从而避免这种问题的发生.
10
11 同步代码块.关键字:synchronized
12 格式:
13 synchronized(对象)
14 {
15 需要被同步的代码.
16 {
17
18 同步的条件:
19 1.必须是多线程,单线程不能用同步.
20 2.必须是多个线程使用同一个锁.
21 必须保证同步中只有一个线程在运行.
22
23 同步的好处:解决了多线程的安全性问题.
24 缺点:每个线程都要判断锁,影响程序运行速度,耗费资源.
25 */
26 class Ticket implements Runnable
27 {
28 private int ticket = 100;
29 Object obj = new Object();
30 public void run()
31 {
32 while(true)
33 {
34 synchronized(obj) //obj相当于锁.
35 {
36 if(ticket>0)
37 {
38 // try{Thread.sleep(10);}catch(Exception e){}
39 System.out.println(Thread.currentThread().getName()+"===卖票====="+ticket--);
40 }
41 }
42 }
43 }
44 }
45
46 class RunnableTicketSafeDemo
47 {
48 public static void main(String args[])
49 {
50 Ticket t = new Ticket(); //t是共享数据.
51
52 Thread t1 = new Thread(t);
53 Thread t2 = new Thread(t);
54 Thread t3 = new Thread(t);
55 Thread t4 = new Thread(t);
56
57 t1.start();
58 t2.start();
59 t3.start();
60 t4.start();
61 }
62 }