因为昨天看一则关于Synchronized(线程安全的帖子),只是觉得有些奇怪,其实当你明白一些基础后,你完全就可以自学Java了,但是OO的思想是要通过大量的实例以及实践形成的。(其实我的OO思想也不是很强烈,也正如neo_q牛人所说:"简单地说继承、封装、多态,在我们的程序中都应该是要能体现出来的")。
我在看线程的时候,并没觉得有多么困难,也可能是我学的根本就不深入。下面进入正题:
线程简介:
谈到线程,就必然要提到另一个概念,那就是进程。一般可以在同一时间内执行多个程序的操作系统都有进程的概念。一个进程就是一个执行中的程序,而每一个进程都有自己独立的一块内存空间、一组系统资源。在进程概念中,每一个进程的内部数据和状态都是完全独立的。Java通过流控制来执行程序流,程序中单个顺序的流控制称为线程,多线程则意味着一个程序的多行语句可以几乎在同一时间内同时运行。(为什么是几乎,不是同时,涉及到计算机原理,暂不多讲)
线程与进程相似,是一段完成某个特定功能的代码,是程序中单个顺序的流控制;但与进程不同的是,同类的多线程是共享一块内存空间和一组系统资源,而线程本身的数据通常只有CPU的寄存器数据,以及一个供程序执行时使用的堆栈。所以系统在产生一个线程,或者在各个线程之间切换时,负担要比进程小的多,所以线程可以被看作是轻量级的进程。一个进程中可以包含多个线程,一个线程是一个程序内部的顺序控制流。
作为Java的一个重要的特性,Java内在支持多线程,它的所有类都是在多线程下定义的、Java利用多线程使整个系统成为异步系统。Java中的线程由3个部分组成:虚拟的CPU、CPU所执行的代码和CPU所处理的数据。
线程体的概念:
虚拟的CPU被封装在java.lang.Thread类中,这样CPU所执行的代码和CPU所处理的数据都传递给java.lang.Thread类的实例中。所以Java的线程是通过java.lang.Thread类来实现的。当我们生成一个Thread 类的对象后,一个新线程就产生了。现成实例表示Java解释器中的真正的线程,通过它可以启动线程、终止线程、线程挂起等。每个线程都是通过某个特定Thread对象的方法run()来完成其操作的,方法run()称为线程体。
Thread类有8个构造函数:略……API中明确写出
Thread类的常用方法:(新手常用)
static Thread currentThread() //静态方法,通过这个方法可以获得主线程的引用,从而达到操作主线程的目的。(什么是主线程?参见主线程)
static int activeCount() //静态方法,获得当前活动线程数量
long getId() //获得当前线程id
String getName() //获得当前线程名字
int getPriority() //获得优先级
boolean isAlive() //当前线程是否处于活动状态。
boolean isDaemon()//是否为守护线程
void run()//run()方法,我们用线程,主要就是对run()方法的重写
void start() // 使该线程开始执行;Java 虚拟机调用该线程的run() 方法。
void sleep() //使当前线程休眠,以执行其他线程,如Thread.sleep(1000) 休眠1秒
其实这些方法API中都有,而且写的都很详细,就不多说了。
线程体的自定义:
Java 中使用线程无非就是对run()方法的重写,你可以通过继承Thread类或者使用Runnable接口来定义你自己的线程。由于Java的单一继承,所以提供了Runable接口。
=======================================================================
写几个简单的例子:
class MyThread extends Thread{//继承Thread实现线程,但是此类将不能再继承别类。
public myThread(String name){
super(name);
}//这是myThread的构造方法,将name传给Thread,name即自定义线程名字
public void run(){
System.out.println("This is myThread :"+this.getName());
for(int i=0;i<10;i++)
System.out.println("This is myThread :"+this.getName()+" : "+i);
}//run()方法的重写
http://hanzhongfuzhuang.com sducc1125}
public class ThreadDemo{
public static void main(String [] args){
MyThread mt = new MyThread("线程1"); //实例化线程1,下文引用的①
MyThread mt1 = new MyThread("线程2");//实例化线程2
mt.start();//线程1运行,下文引用的②
mt1.start();//线程2运行
}
}
=====================================================================
class MyThread implements Runnable{ //接口实现线程
private Thread myThread = null;
public myThread(String name){
super();
this.myThread = new Thread(this,name);
}//这是myThread的构造方法。
public void start(){
myThread.start();
}//由于接口Runnable中,只有一个抽象run()方法,所以我们要定义一个start()方法,使当前线程运行。
public void run(){
System.out.println("This is myThread :"+this.getName());
for(int i=0;i<10;i++)
System.out.println("This is myThread :"+this.getName()+" : "+i);
}//run()方法的重写
}
//main()方法基本一样,就不写了,由于以上代码都是在这里写的,在baidu blog中tab不好使,所以……丑
//这里我主要想说明的是线程的两种实现方式,一是继承Thread,二使用Runnable接口。
==========================================================================
线程的状态:
线程的状态有4种:创建状态、可执行状态、不可执行状态、死亡状态。
创建状态:实例化线程对象后,线程就处于创建状态,此时系统不为它分配资源。接上文①位置。
可执行状态:当调用了run()方法后,线程就处于可运行状态,系统为他分配了它需要的系统资源。这里要注意可运行与运行之分,调用了run()方法,并不代表它正在运行,同一时刻只能运行处于可运行状态的的线程中的一个。
不可运行状态:不可运行状态也称为组塞状态,由于某中圆心系统不能执行线程的状态。在这种情况下,即便CPU空闲,线程也不能被执行。线程成为不可能运行状态可能因为:Ⅰ.调用了sleep()方法。Ⅱ.调用了suspend()方法。Ⅲ.调用了wait()方法。Ⅳ.输入输出流中发生线程阻塞。
死亡状态:线程执行完会自动进入死亡状态或是调用了stop()方法都会进入死亡状态。stop()方法已经过时。
主线程:
Java程序启动运行时JVM会自动创建一个现成,这个就是主线程。
主线程的重要性和特殊性表现在下面两个方面:
1。他是产生其他线程的线程。
2。它通常执行各种关闭操作,是最后结束的。
在这里你可以理解main()为一个主线程。只有main()的产生,你才可以new出新的myThread线程对象。
线程调度:
在没有设置优先级的情况下,Java提供了一个线程调度器来调度程序启动后进入可运行状态的所有线程。线程调度器按线程的优先级高低选择优先级高的先执行。
线程调度是抢先式调度,即当前线程执行过程中,一个更高级的线程进入可运行状态,将暂停原线程的运行,去执行更高级的线程。
抢先式调度又分为:时间片方式和独占方式。时间片方式可以理解为按一定时间执行各个处于可运行状态的线程,当时间到时,不管是否执行完,都转入对下一个线程的执行。独占方式则是指CPU始终在执行一个线程,只有当前线程执行完后或线程主动退出后,才转入对下一个线程的执行。
线程优先级:
Java中线程有10个优先级,由低到高分别用1~10表示。Thread类中定义了3个静态变量,分别是Thread.MIN_PRIORITY 代表最低优先级1,Thread.NORM_PRIORITY 普通5,Thread.MAX_PRIORITY 最高10
我们可以通过setPriority(),以及getPriority()对当前线程优先级进行操作。
假如有myThread0,myThread1,以及myThread2、三个线程同时处于可运行状态,分别对应min、norm、max优先级,那CPU将会先执行优先级为max、再执行norm、最后执行min的run()方法。
守护线程:(精灵线程)
线程默认都是非守护线程,非守护线程也称做用户线程。程序中当所有用户线程都结束时,守护线程也立即结束。因为守护现成随时会结束,所以守护线程所做的工作应该是可以随后结束而不应该运行结果的工作。
我们通过setDaemon(boolean on)来设置当前线程是否为守护线程。还是上面的继承Thread的例子,我们再多写一个MyThread2,其中run()方法为
while(true)
System.out.println("This is Daemon Thread");
并且在main()中这样写
MyThread2 mtDaemon = new MyThread2("DaemonThread");
mtDaemon.start();
mtDaemon.setDaemon(true);
假如没有setDaemon()这句,mtDaemon线程将进入死循环,并导致正个程序都不能停止,而如果设置了setDaemon()后当mt线程进入死亡状态后,main()也结束时,mtDaemon也伴随结束。一般守护线程可以用于程序的自动更新什么的。
线程同步:(线程安全)
当有多个线程共享一个变量时,需要确保资源在某一个时刻只有一个线程占用,这个过程就是线程同步。
举例说明:假如有3个人同时在拨打同1个电话号码,这3个人好比3个可运行状态的线程,都在拨打的电话号码就是共享变量。而当前电话不可能被3个人同时拨通,只有第1个被接通人的电话挂断,其他2个人的1个才能被接进来,第2个人再挂断电话,第3个人才能接近来。
这里主要用到的就是synchronized关键字。我这里有一个例子:
============================================================================
class PhoneCalls{
private String phoneName = "";
public PhoneCalls(String name) {
this.phoneName = name;
}
public void call(String name){
try{
System.out.println("<---"+name+"拨打"+this.phoneName+"电话--->");
Thread.sleep(1000);
System.out.println("<---"+name+"正在通话ing--->");
Thread.sleep(1000);
System.out.println("<---"+name+"挂断电话--->");
}catch(Exception e){
e.printStackTrace();
}
}
}
public class SynCalls implements Runnable{
private String name = "";
private PhoneCalls phone = null;
private Thread thread = null;
public SynCalls(String name,PhoneCalls phone) {
this.name = name;
this.phone = phone;
this.thread = new Thread(this);
}
public void start(){
this.thread.start();
}
public void run() {
synchronized (this.phone) {
this.phone.call(this.name);
}
}
public static void main(String [] args){
PhoneCalls phone = new PhoneCalls("狗剩的电话");
SynCalls frist = new SynCalls("张三",phone);
SynCalls second = new SynCalls("李四",phone);
SynCalls third = new SynCalls("王五",phone);
frist.start();
second.start();
third.start();
}
}
/
1.进一步巩固java基础。thinking in java必须看完,而且是一字不差地读完,所有讲到的知识点都要写testcase,而且这本书最大的好处是在你不知不觉中培养你的OO思想,对你应该有所帮助,这本书至少读两遍,视你的情况而定如果第二遍不能全部理解,那么再来一轮直到真的全部理解,之后你可以看看effective in java,为什么你到时候我相信会明白的。
2.逐步从写出代码到写好代码过渡。这个不是一蹴而就的,一定要在写的过程中慢慢培养一种思考方式和编程的习惯,那是什么样的习惯呢?重构的习惯,至于重构是怎么会事情,简单说就是写完了重写一遍,你千万别觉得这个是麻烦事情,他的帮助是很大的,会告诉你如果下次遇到这样的情况,那么你就会按照好的那种方法来写。至于如何做到有两本书可以帮助你,Martin Fowler写的《重构》,Steve McConnell《代码大全》第二版。看完这两本书,你会再上一个层次。
接下来还有很长的路,希望对你有所帮助,如果你觉得我这是废话,那么请完全忽略。:)
另外一句话,swing的东西还是少做点,尽快转向J2EE吧,毕竟外面的企业中还是J2EE较多,但是如果你真的喜欢做桌面的话,或者兴趣在此,那么当我没说。