◆需要从JavalangThread类派生一个新的线程类,重载它的run()方法;
◆实现Runnalbe接口,重载Runnalbe接口中的run()方法。
为什么Java要提供两种方法来创建线程呢?它们都有哪些区别?相比而言,哪一种方法更好呢?
在Java中,类仅支持单继承,也就是说,当定义一个新的类的时候,它只能扩展一个外部类这样,如果创建自定义线程类的时候是通过扩展 Thread类的方法来实现的,那么这个自定义类就不能再去扩展其他的类,也就无法实现更加复杂的功能。因此,如果自定义类必须扩展其他的类,那么就可以使用实现Runnable接口的方法来定义该类为线程类,这样就可以避免Java单继承所带来的局限性。
还有一点最重要的就是使用实现Runnable接口的方式创建的线程可以处理同一资源,从而实现资源的共享
(1)通过扩展Thread类来创建多线程
假设一个影院有三个售票口,分别用于向儿童、成人和老人售票。影院为每个窗口放有100张票,分别是儿童票、成人票和老人票。三个窗口需要同时卖票,而现在只有一个售票员,这个售票员就相当于一个CPU,三个窗口就相当于三个线程。通过程序来看一看是如何创建这三个线程的。
public class MutliThreadDemo {
public static void main(String [] args){
MutliThread m1=new MutliThread("Window 1");
MutliThread m2=new MutliThread("Window 2");
MutliThread m3=new MutliThread("Window 3");
m1start();
m2start();
m3start();
}
}
class MutliThread extends Thread{
private int ticket=100;//每个线程都拥有100张票
MutliThread(String name){
super(name);//调用父类带参数的构造方法
}
public void run(){
while(ticket>0){
Systemoutprintln(ticket--+" is saled by "+ThreadcurrentThread()getName());
}
}
}
程序中定义一个线程类,它扩展了Thread类。利用扩展的线程类在MutliThreadDemo类的主方法中创建了三个线程对象,并通过start()方法分别将它们启动。
从结果可以看到,每个线程分别对应100张票,之间并无任何关系,这就说明每个线程之间是平等的,没有优先级关系,因此都有机会得到CPU的处理。但是结果显示这三个线程并不是依次交替执行,而是在三个线程同时被执行的情况下,有的线程被分配时间片的机会多,票被提前卖完,而有的线程被分配时间片的机会比较少,票迟一些卖完。
可见,利用扩展Thread类创建的多个线程,虽然执行的是相同的代码,但彼此相互独立,且各自拥有自己的资源,互不干扰。
(2)通过实现Runnable接口来创建多线程
public class MutliThreadDemo2 {
public static void main(String [] args){
MutliThread m1=new MutliThread("Window 1");
MutliThread m2=new MutliThread("Window 2");
MutliThread m3=new MutliThread("Window 3");
Thread t1=new Thread(m1);
Thread t2=new Thread(m2);
Thread t3=new Thread(m3);
t1start();
t2start();
t3start();
}
}
class MutliThread implements Runnable{
private int ticket=100;//每个线程都拥有100张票
private String name;
MutliThread(String name){
thisname=name;
}
public void run(){
while(ticket>0){
Systemoutprintln(ticket--+" is saled by "+name);
}
}
}
由于这三个线程也是彼此独立,各自拥有自己的资源,即100张票,因此程序输出的结果和(1)结果大同小异。均是各自线程对自己的100张票进行单独的处理,互不影响。
可见,只要现实的情况要求保证新建线程彼此相互独立,各自拥有资源,且互不干扰,采用哪个方式来创建多线程都是可以的。因为这两种方式创建的多线程程序能够实现相同的功能。
由于这三个线程也是彼此独立,各自拥有自己的资源,即100张票,因此程序输出的结果和例421的结果大同小异。均是各自线程对自己的100张票进行单独的处理,互不影响。
可见,只要现实的情况要求保证新建线程彼此相互独立,各自拥有资源,且互不干扰,采用哪个方式来创建多线程都是可以的。因为这两种方式创建的多线程程序能够实现相同的功能。
(3)通过实现Runnable接口来实现线程间的资源共享
现实中也存在这样的情况,比如模拟一个火车站的售票系统,假如当日从A地发往B地的火车票只有100张,且允许所有窗口卖这100张票,那么每一个窗口也相当于一个线程,但是这时和前面的例子不同之处就在于所有线程处理的资源是同一个资源,即100张车票。如果还用前面的方式来创建线程显然是无法实现的,这种情况该怎样处理呢?看下面这个程序,程序代码如下所示:
+ View Code
结果正如前面分析的那样,程序在内存中仅创建了一个资源,而新建的三个线程都是基于访问这同一资源的,并且由于每个线程上所运行的是相同的代码,因此它们执行的功能也是相同的。
可见,如果现实问题中要求必须创建多个线程来执行同一任务,而且这多个线程之间还将共享同一个资源,那么就可以使用实现Runnable接口的方式来创建多线程程序。而这一功能通过扩展Thread类是无法实现的,读者想想看,为什么?
实现Runnable接口相对于扩展Thread类来说,具有无可比拟的优势。这种方式不仅有利于程序的健壮性,使代码能够被多个线程共享,而且代码和数据资源相对独立,从而特别适合多个具有相同代码的线程去处理同一资源的情况。这样一来,线程、代码和数据资源三者有效分离,很好地体现了面向对象程序设计的思想。因此,几乎所有的多线程程序都是通过实现Runnable接口的方式来完成的。基本的是两种:
第一种是继承Tread class:
class PrimeThread extends Thread { long minPrime; PrimeThread(long minPrime) { thisminPrime = minPrime; } public void run() { // compute primes larger than minPrime } }
在main里:
PrimeThread p = new PrimeThread(143); pstart();
还有就一种是implements Runnable:
public class HelloRunnable implements Runnable { public void run() { Systemoutprintln("Hello from a thread!"); } public static void main(String args[]) { (new Thread(new HelloRunnable()))start(); }}
同样用 xxxstart() 可以运行这个线程
这是基本的,还有就是管理一群线程(threads pool),可以用executor以及executor service, 以上信息都可以在oracle网找到很多例子一般有两种
1用接口
Runnable
class
A
implements
Runnable
{
public
void
run()
{
Systemoutprintln("hi
你好!\n");
}
}
public
class
B
{
public
static
void
main(String[]
args)
{
A
aa
=
new
A();
Thread
t
=
new
Thread(aa);//这里要new一个对象
因为在Runnable里没有run方法所以要用你自己定义的
详细看帮助文档
tstart();
Systemoutprintln("你好!你好!
你好!\n
\n\n\n");
}
}
2
继承
Threads
class
A
extends
Threands
{
public
void
run()
//run()
是Threads
的一个方法
他的默认是空的
你需要重写一个run方法
{
Systemoutprintln("hi
你好!\n");
}
}
public
class
B
{
public
static
void
main(String[]
args)
{
A
aa
=
new
A();
aastart();
Systemout
println("你好!你好!
你好!\n
\n\n\n");
}
}java中多线程的实现方式有两种,一种是继承javalangThread类,另一种是实现javalangRunnable接口。下面是两种方式的简单代码。继承Thread类方式:import javalangThread; //用集成Thread类方式实现多线程。 public class Test{ public static void main(String arg[]){ T t1=new T(); T t2=new T(); //更改新线程名称 t1setName("t1"); t2setName("t2"); //启动线程 t1start(); t2start(); } } class T extends Thread{ //重写run()方法 public void run(){ Systemoutprintln(thisgetName()); } }输出结果为:t1t2实现Runnable接口方式:在使用Runnable接口时需要建立一个Thread实例。因此,无论是通过Thread类还是Runnable接口建立线程,都必须建立Thread类或它的子类的实例。import javalang; //用实现Runnable接口的方式实现多线程。 public class Test{ public static void main(String arg[]){ T t1=new T(); T t2=new T(); //一定要实例化Thread对象,将实现Runnable接口的对象作为参数传入。 Thread th1=new Thread(t1,"t1"); Thread th2=new Thread(t2,"t2"); //启动线程 th1start(); th2start(); } } class T implements Runnable{ //重写run()方法 public void run(){ Systemoutprintln(ThreadcurrentThread()getName()); } }输出结果为:t1t2public void run()方法是JAVA中线程的执行体方法,所有线程的 *** 作都是从run方法开始,有点类似于main()方法,即主线程。首先子线程起成相同的名字threadsetName("smallThread");
进行循环调用,通过ThreadactiveCount();得到开启的线程总数的个数
假如要管理一个线程通过以下方法:
private
int
getThreadCount(){
int
count
=
0;
Map
allStackTraces
=
ThreadgetAllStackTraces();
Set
keySet
=
allStackTraceskeySet();
Iterator
iterator
=
keySetiterator();
while(iteratorhasNext()){
Thread
thread
=
iteratornext();
if(threadgetName()equals("smallThread")){
count++;
}
}
return
count;
}
注意在开启每个线程的时候给每个线程起一个固定的名字,控制线程数的时候通过名字来进行判断和控制。1
2
3
4
5
6
7
8
9
10
11
创建线程,就是这样
extends Thread 或者 implements Runnable,但是有很多问题;
所以引申出了下面的线程池
Java通过Executors提供四种线程池,分别为:
newCachedThreadPool创建一个可缓存线程池,如果线程池长度超过处理需要,可灵活回收空闲线程,
若无可回收,则新建线程。
newFixedThreadPool 创建一个定长线程池,可控制线程最大并发数,超出的线程会在队列中等待。
newScheduledThreadPool 创建一个定长线程池,支持定时及周期性任务执行。
newSingleThreadExecutor 创建一个单线程化的线程池,它只会用唯一的工作线程来执行任务,
保证所有任务按照指定顺序(FIFO, LIFO, 优先级)执行。class test {
private static int s = 2000;
public synchronized static void sub(int m){//自定义方法,可以类比于自定义异常
int temp = s;
temp = temp - m;
try {
Threadsleep((int)(Mathrandom() 1000));
}catch (Exception e){
Systemoutprintln(egetMessage());
}
s = temp;
Systemoutprintln("s = " + s);
}
}
class Customer extends Thread{
public void run(){//调用run()方法,运行run()方法中的程序片
for(int i = 1;i <= 4;i++){
testsub(100);
//当线程cus1没有结束对sub方法的使用之前,cus2无法进入并运行此方法
//synchronized的作用就在于此
}
}
}
public class Synchronizedtest{
public static void main(String[] args){
Customer cus1 = new Customer();
Customer cus2 = new Customer();
cus1start();
cus2start();
}
}
自己研究下吧
线程据我所知在开发大型项目的时候才会用到都是通过new
Thread()start()开启线程,一般有两种方式:1是继承自Thread类,2是实现Runnable接口,第二种方式更加灵活,Java不支持多继承,但是支持多实现。求采纳
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)