进程与线程
进程
一个程序的每一次运行称为进程
实际上,进程不是同时运行的,对于一个 CPU 而言,某个时间段只能运行一个程序,也就是只能执行一个进程。操作系统会为每个进程分配一段有限的 CPU 使用时间,CPU 在这段时间内执行某个进程,然后会在下一段时间切换到另一个进程中去执行。
线程
在一个进程中还可以有多个执行单元同时运行,这些执行单元被称为线程,线程是比进程更小的执行单元。
多线程指同一个程序进程内,多个线程同时执行。
主线程
程序启动运行main时候,java虚拟机启动一个进程,主线程main在main()调用时候被创建。
线程的创建与实现
1.通过继承Thread类
该类继承Thread类,创建这个类的对象时就可以产生一个新的线程。通过该类中重写run()方法、子类的实例对象使用start()方法启动线程。线程启动后,系统会自动调用 run() 方法。
Thread类:直接继承于Object,实现了Runnable接口。
package test_thread;
class Cat extends Thread
{
public void run()
{
for(int i=0;i<55555;i++)
if(i%10000==0)
System.out.println("cattttttttttttttttttttt");
}
}
class Dog extends Thread
{
public void run()
{
for(int i=0;i<55555;i++)
if(i%10000==0)
System.out.println("doggggggggggggggggggggg");
}
}
public class Test_Thread {
public static void main(String[] args) {
Cat c = new Cat();
Dog d = new Dog();
c.start();
d.start();
}
}
/*
run:
cattttttttttttttttttttt
doggggggggggggggggggggg
cattttttttttttttttttttt
doggggggggggggggggggggg
doggggggggggggggggggggg
doggggggggggggggggggggg
cattttttttttttttttttttt
doggggggggggggggggggggg
doggggggggggggggggggggg
cattttttttttttttttttttt
cattttttttttttttttttttt
cattttttttttttttttttttt
成功构建 (总时间: 0 秒)
*/
2.越过Thread类直接实现Runnable接口
由于Java中只支持单继承,一个类如果继承了某个父类就不能再继承 Thread 类了。为了克服弊端,Thread 类提供了另一个构造方法 Thread(Runnable target),该方法中,Runnable 是一个接口,它只有一个 run() 方法。
当应用时, 需要先通过Thread类的构造方法Thread(Runnable target) 构造出对象 ,通过new Thread(c).start启动进程,此时该实例对象作为Thread构造方法的参数。
package test_thread;
class Cat implements Runnable
{
public void run()
{
for(int i=0;i<55555;i++)
if(i%10000==0)
System.out.println("cattttttttttttttttttttt");
}
}
class Dog implements Runnable
{
public void run()
{
for(int i=0;i<55555;i++)
if(i%10000==0)
System.out.println("doggggggggggggggggggggg");
}
}
public class Test_Thread {
public static void main(String[] args) {
Cat c = new Cat();
Dog d = new Dog();
new Thread(c).start();
new Thread(d).start();
}
}
/*
run:
cattttttttttttttttttttt
doggggggggggggggggggggg
cattttttttttttttttttttt
doggggggggggggggggggggg
cattttttttttttttttttttt
doggggggggggggggggggggg
doggggggggggggggggggggg
cattttttttttttttttttttt
doggggggggggggggggggggg
doggggggggggggggggggggg
cattttttttttttttttttttt
cattttttttttttttttttttt
成功构建 (总时间: 0 秒)
*/
线程的生命周期与状态
生命周期状态图
基本状态
–诞生状态:线程刚刚被创建
–就绪状态:线程已准备好运行,执行start方法
–运行状态:处理机分配给了线程,线程正在运行
–阻塞状态:等待其他线程释放互斥资源时
–休眠状态:执行sleep方法而进入休眠
–死亡状态:线程已完成或退出
线程优先级
(没听懂,有空再更)
常用方法
Thread()
构造一个新的线程对象,默认名为Thread-n,n是从0开始递增的整数。
Thread(String name)
构造一个新的线程对象,并同时指定线程名。
getName()
返回此线程的名称。
isAlive()
测试这个线程是否还处于活动状态。
活动状态就是线程已经启动且尚未终止。线程处于正在运行或准备运行的状态。
sleep(long millis)
使当前正在执行的线程以指定的毫秒数“休眠”(暂时停止执行),具体取决于系统定时器和调度程序的精度和准确性。
interrupt()
只是给另一个线程发送一个中断信号,到底该线程是否处理中断信号由该线程自行处理。
interrupted() 和isInterrupted()
interrupted():测试当前线程是否已经是中断状态,执行后具有将状态标志清除为false的功能。
isInterrupted(): 测试线程Thread对相关是否已经是中断状态,但不清楚状态标志。
setName(String name)
将此线程的名称更改为等于参数 name 。
join()
在很多情况下,主线程生成并起动了子线程,如果子线程里要进行大量的耗时的运算,主线程往往将于子线程之前结束,但是如果主线程处理完其他的事务后,需要用到子线程的处理结果,也就是主线程需要等待子线程执行完成之后再结束,这个时候就要用到join()方法了。
join()的作用是:“等待该线程终止”,这里需要理解的就是该线程是指的主线程等待子线程的终止。也就是在子线程调用了join()方法后面的代码,只有等到子线程结束了才能执行。
yield()
yield()方法的作用是放弃当前的CPU资源,将它让给其他的任务去占用CPU时间。注意:放弃的时间不确定,可能一会就会重新获得CPU时间片。
线程同步
当多个线程需要处理同一个数据时,需要做同步处理。
理解成多线程运行相当于不同道路的车同时在开,然后当他们同时走到一个窄路口的时候(就是调用同一个方法的时候 ),让车一个个过。——来自祥硕哥哥的理解
措施: 把synchronized关键字加在互斥的方法上 , 保证一段代码在多线程执行时是互斥的
GUI初步
通过多线程技术(其实没用),使用sleep()方法,实现进度条的动态更新效果。
class Controller extends Thread
{
JProgressBar jpb;
Controller(JProgressBar jpb)
{
this.jpb=jpb;
}
public void run()
{
for(int i=0;i<=jpb.getMaximum();i++)
{
try {
jpb.setValue(i);
sleep(50);
} catch (InterruptedException ex) {
Logger.getLogger(Controller.class.getName()).log(Level.SEVERE, null, ex);
}
}
}
}
new Controller(jindu).start();
/*启动线程,可以放在窗体的构造方法中运行即启动,也可以放在鼠标、键盘事件中启动。*/