线程上

第十章 线程

10.1线程的概念:

事实上,在单个程序内部是可以在同一时刻进行多种运算的,这就是所谓的多进程(这与多任务的概念有相似之处)。、

一个单独的进程与顺序程序相似,也有一个入口,一个出口,以及一个顺序执行的序列。从概念上说,一个线程是一个程序内部的一个顺序控制流。线程并不是程序,它自己本身并不能运行,而必须在程序中运行。在一个程序中可以实现多个进程,这些进程同时运行,但是多线程并不等于多次启动一个程序,操作系统也不会把每个线程当做进程来对待。

线程如进程的区别:

1:两者的颗粒度不同,是两个不同层次上的概念。进程是由操作系统来管理的,而线程则是在一个程序(进程)内。

2:不同的的代码,内部数据和状态都是完全独立的,而一个程序内的多线程共享同一块内存空间和同一组系统资源,有可能互相影响。

3:线程本身的数据通常只有寄存器数据,以及一个程序执行时使用的堆栈,所以线程的切换负担比进程切换有的要小。

使用多线程具有的如下的优点:

1:多线程编程简单,效率高(能直接共享数据和资源,而多进程不能)

2:适合于开发服务程序(如web服务,聊天服务)

3:适合于开发有多种交互接口的程序(如聊天程序的客户端,网路下载工具)

4:适合于有人机交互又有计算量的程序

5:减轻编写交互频繁,涉及面多的程序的困难(如监听网络接口)

6:程序的吞吐量会得到改善

7:有多个处理器的系统,可以并发运行不同的线程

10.2线程的建立

Java提供了类Java.lang.Thread来支持多线程编程,Thread类有以下的构造方法

Thread()

Thread(Runable target)

Thread(Runable target,String name)

Thread(String name)

Thread(ThreadGroup group,Rnuable target)

Thread(ThreadGroup group,Rnuable target,String name)

Thread(ThreadGroup group,String name)

参数target是线程执行的目标对象,即线程执行的代码;group是线程所在的组;name是线程的名字

10.2.1采用继承法创建线程

该方法比较简单,主要是通过继承java.lang.Thread,并覆盖Thread类的run()方法来完成线程的创建.Thread类是一个具体的类不是抽象类,该类封装了线程的行为.要创建一个线程,程序员必须创建一个Thread的子类.Thread类中最重要的方法时run()start().

Run()方法必须进行重写,把线程所要执行的代码加入到这个方法中,也就是线程体.但是它必须经过start()方法来启动线程.

public class MyThread extends Thread

{

// count变量用于统计打印的次数并共享变量

private static int count = 0;

public static void main(String[] args)

{

MyThread p = new MyThread("t1");

// 线程执行

p.start();

// 主线程main方法执行一个循环

for (int i = 0; i < 5; i++)

{

count++;

System.out.println(count + " :main");

}

}

// 构造方法

public MyThread(String name)

{

// 调用父类的构造方法

super(name);

}

@Override

public void run()

{

// 线程中必须有的run方法

for (int i = 0; i < 5; i++)

{

count++;

System.out.println(count + ":" + this.getName());

}

}

}

10.2.2 通过实现接口创建线程

该方法通过实现java.lang.Runnable接口的类来创建多线程.该接口定义了一个方法run(),所以必须的新类中实现它,但是Runnable接口中没有任何对线程的支持,还必须要创建Thread类的实例

public class MyThread2 implements Runnable

{

public static void main(String[] args)

{

for (int i = 0; i < 5; i++)

{

new Thread(new MyThread2(i + 1)).start();

}

}

int count, number;

public MyThread2(int i)

{

this.number = i;

System.out.println("创建线程 " + this.number);

}

public void run()

{

while (true)

{

System.out.println("线程 " + this.number + ":计数 " + this.count);

if (++this.count == 6)

{

return;

}

}

}

}

10.3线程的生命周期及调度

10.3.1 线程的生命周期

线程是动态的,具有一定的生命周期,分别从创建,执行,堵塞直到死亡.在每一个线程类中都定义了用于完成功能的run方法,这个方法称为线程体

1:线程的四个状态

1.1:创建状态:

当利用new关键字创建线程对象实例后,它仅仅作为一个对象实例存在,JVM没有为其分配CPU时间片等线程资源

1.2:就绪状态:

当处于创建状态的线程中调用start方法将线程的状态转换为就绪状态.

1.3:堵塞状态

堵塞指的是暂停一个线程的执行以等待某个条件发生(如某资源准备就绪),若线程处于堵塞状态,调度机制不给它分配任何CPU时间,直接跳过它.

1.4:死亡状态

当线程运行结束或者在调用线程对象的stop方法后线程将终止运行,JVM收回线程占用的资源

10.3.2:线程调度和优先级

Java采用的是一种简单,固定的调度法,即固定优先级调度(抢先式调度),Java将线程的优先级分为10个等级,分别用110的数字表示.数字越大表明线程的级别越高.相应的,Thread类中定义了表示线程最高,最低,和普通优先级的常量MIN_PRIORITY,MAX_PRIORITY,NORMAL_PRIORITY,代表的优先级分别是1,10,5,当一个线程对象被创建时,其默认的优先级是5.

在应用程序中设置线程优先级的方法比较简单,在创建线程对象后可以调用线程对象的setPriority()方法该表线程的优先级,同样可以调用getPriority()来获取当前线程的优先级.

public class TestThreadPriority extends Thread

{

public static void main(String[] args)

{

TestThreadPriority t1 = new TestThreadPriority("Thread1");

t1.setPriority(MIN_PRIORITY);

t1.start();

TestThreadPriority t2 = new TestThreadPriority("Thread2");

t2.setPriority(NORM_PRIORITY);

t2.start();

TestThreadPriority t3 = new TestThreadPriority("Thread3");

t3.setPriority(MAX_PRIORITY);

t3.start();

}

public TestThreadPriority(String name)

{

super(name);

}

@Override

public void run()

{

for (int i = 0; i < 3; i++)

{

System.out.println(this.getName() + " is running");

}

super.run();

}

}

10.4:线程互斥

在并发程序设计中已经被研究并得到解决.对多线程共享的资源或数据称为临界资源,而把每一个线程中访问临界资源的那一段代码称为临界代码.通过为临界带买段设置信号灯,就可以保证资源的完整性,从而安全地访问共享资源.

为了实现这种机制,Java语言提供了以下两方面的支持

为每个对象设置了一个互斥锁标记.该标记保证在任何时候,只能有一个线程有该互斥锁,其他线程如果需要获得互斥锁,必须等待当前拥有该锁的线程将其释放.该对象称为互斥对象.

为了配合使用对象的互斥锁,Java语言提供了保留字synchronized.其基本用法如下:

Synchronized(互斥对象){

临界代码

}

当一个线程执行到该行代码时,首先检测该互斥对象的互斥锁.如果该互斥锁没有被占用,则该线程将获得该互斥锁,并执行临界代码,直到执行完毕并释放互斥锁;

可以看出,任意一个对象都可以作为信息灯,从而解决上面的问题,首先定义一个互斥对象类,作为信号灯.由于该对象只作为信号量使用,所以并不需要为它定义其他方法.

public class AccountThread extends Thread

{

public static void main(String[] args)

{

Account account = new Account(100);

Semaphore semaphore = new Semaphore();

AccountThread at1 = new AccountThread(account, 1000, semaphore);

AccountThread at2 = new AccountThread(account, 0, semaphore);

at1.start();

at2.start();

}

Account account;

int delay;

Semaphore semaphore;

// 构造方法

public AccountThread(Account account, int delay, Semaphore semaphore)

{

this.account = account;

this.delay = delay;

this.semaphore = semaphore;

}

@Override

public void run()

{

synchronized (this.semaphore)

{

if (this.account.balance >= 100)

{

try

{

// 延迟

sleep(this.delay);

// 模拟取钱100

this.account.balance = this.account.balance - 100;

System.out.println("withdraw 100 successful!!!");

}

catch (InterruptedException e)

{

e.printStackTrace();

}

}

else

{

System.out.println("withdraw failed!!!");

}}}}

// 定义一个类,利用其对象作为互斥信号灯

class Semaphore{}

posted @ 2016-11-01 19:23  qingtianBKY  阅读(225)  评论(0编辑  收藏  举报