线程

1.进程与线程的定义:

进程:程序的一次执行过程,对应了从代码的加载,执行到执行结束这样一个完整的过程,也是进程从产生,发展到消亡的过程.每个进程在计算机的内存中都对应一段专有的内存空间,现在的操作系统都支持多进程操作,比如:计算机可以同时播放视频,声音,同时还可以上网,聊天等.

线程:比进程更小的执行单元,单个进程的执行可以产生多个线程

2.线程的创建:

(1)继承Thread类

public static void main(String[] args)

{

Thread t = Thread.currentThread();//通过调用Thread类的currentThread()静态方法获得当前主线程的引用

System.out.println("当前的主线程是:" + t);

t.setName("MyThread1");//修改主线程的名称为MyThread1

System.out.println("当前主线程是:" + t);//当前主线程是:Thread[MyThread1,5,main]:MyThread1代表主线程的名称,5代表它的优先级,main代表线程组

MyThread1 mt = new MyThread1();//创建子线程mt

mt.start();//启动了刚创建的子线程mt,执行线程类的run()方法

}

public void run(){

int sum = 0;

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

{

sum = sum + i;

}

System.out.println("1+2+3+...+100=" + sum);

}

结果:

当前主线程是:Thread[main,5,main]

当前主线程是:Thread[MyThread1,5,main]

1+2+3+...+100=5050

//重写了Thread类的run方法,实现自定义的功能,如果不重写run()方法,程序正常运行,只是此时的子线程不完成任何功能;子线程mt的启动是在主线程中实现的,而子线程在运行完run()方法后也自动终止了.

(2)实现Runnable接口(由于java语言规定的单一继承原则,所以如果希望用户自定义的类继续其他类,此时可以通过实现Runnable接口的方式使用线程)

public static void main(String[] args)

{

Thread t = new Thread(new SimpleThread(),"线程1");

t.start();

System.out.println("主线程运行结束");//此时主线程已经运行结束,而子线程的run()方法此时还在运行.显然两个线程的运行是相互独立的,主线程只能启动子线程的运行,而不能终止它的运行.

}

@Override

public void run()

{

int i = 1;

while(i <= 10){

try

{

System.out.println("*");

Thread.sleep(1000);

catch (InterruptedException e)

{

e.printStackTrace();

}

i++;

}

}

结果:

主线程运行结束

**********

 

3.线程的生命周期:线程从创建到死亡的整个过程称为线程的一个"生命周期"

4.线程的优先级:

MAX_PRIORITY:线程的最高优先级,代表常量值10

NORM_PRIORITY:线程的默认优先级,代表常量值5

MIN_PRIORITY:线程的最低优先级,代表常量值1

设置和获取优先级的方法:

void setPriority(int newPriority);

int getPriority()

5.线程的同步:

通过线程的优先级可以设置线程占用CPU时间的策略,保证多个线程能合理地,顺序地占用CPU时间片,执行自己的run()方法.但是,如果出现多个线程同时操作一个共享资源,比如打印机,文件等,如何分配多个线程对打印机的操作和控制呢?

为了处理这种对共享资源的竞争,Java语言提供了线程的同步机制.所谓同步机制是指两个或者多个线程同时访问一个对象时,应该保证对象的统一性和完整性.同步是基于"监视器"的概念,类似于平时说的"黑盒子",一旦某个线程获得控制权后,其他线程只能等待,直到原先的线程放弃对"黑盒子"的控制,其他线程才能获得对"黑盒子"的控制权.

Java语言提供了对线程同步的内置支持,通过使用Java语言提供的synchronized关键字,可以采用同步方法或同步代码块的方法实现线程的同步,具体使用哪种根据具体情况而定.

同步方法:

同步方法是指将访问共享资源的方法标记为synchronized,这样当某个线程调用了该方法后,其他调用该方法的线程将进入阻塞状态,直到原线程完成对synchronized方法的调用为止.

public class SyncExample extends Thread

{

private char ch;

public SyncExample(char ch){

this.ch = ch;

}

public void run(){

PrintCH.print(ch);

}

public static void main(String[] args)

{

SyncExample t1 = new SyncExample('A');

SyncExample t2 = new SyncExample('B');

t1.start();

t2.start();

}

}

class PrintCH{

public static /*synchronized*/ void print(char c){

for(int i = 0; i < 4; i++){

System.out.print(c);

try

{

Thread.sleep(1000);

catch (InterruptedException e)

{

e.printStackTrace();

}

}

}

}

没有加synchronized结果是杂乱无章的:可能这样BAABABBA,也可能这样BABABABA,若在print方法前面加上synchronized,定义为同步方法,则当线程t1调用该方法执行后,线程t2进入休眠状态,直到该方法执行完毕后,线程t2才能调用该方法,这样保证在同一时刻,只偶有一个print()方法在运行,向控制台输出了字符.这样结果为AAAABBBB

同步代码块:

格式:synchronized(object){

//要同步的语句

}

其中object是需要被同步的对象的引用.一个同步块在调用object对象的某个方法之前,必须确保所在线程能够访问object对象,获得该对象的控制权.在某一时刻,只能有一个线程获得该对象的控制权,从而保证一次只能有一个线程执行该同步块.

public class SyncExample extends Thread

{

private char ch;

private static PrintCH myprint = new PrintCH();

public SyncExample(char ch){

this.ch = ch;

}

public void run(){

synchronized(myprint){

myprint.print(ch);

}

}

public static void main(String[] args)

{

SyncExample t1 = new SyncExample('A');

SyncExample t2 = new SyncExample('B');

t1.start();

t2.start();

}

}

class PrintCH{

public void print(char c){

for(int i = 0; i < 4; i++){

System.out.print(c);

try

{

Thread.sleep(1000);

catch (InterruptedException e)

{

e.printStackTrace();

}

}

}

}

结果:AAAABBBB

6.wait-notify机制:

Java语言通过使用wait(),notify()和notifyAll()方法实现线程间的通信,从而尽量避免多线程运行时出现的"死锁"情况.

在使用wait(),notify()和notifyAll()这三个方法时,注意:

(1)线程调用wait()方法并进入等待状态时,hi释放已经控制的共享资源,必须由当前线程自己调用wait()方法,即:是线程本身在得不到需要的资源时,主动放弃对已有资源的控制,进入等待状态.

(2)线程调用notify()和notifyAll()方法时,是在当前线程已经使用完所控制的共享资源,并且已经放弃了对共享资源的控制时,通知其他线程恢复执行.

(3)线程不能自己调用notify()或者notifyAll()方法唤醒自己;线程不能调用wait()方法要求其他线程进入等待状态.

public class WaitNotiExample

{

public static void main(String[] args)

{

final ChopStick[] chopSticks = new ChopStick[4];

final Philosopher[] philos = new Philosopher[4];

for(int i = 0; i < 4; i++){

chopSticks[i] = new ChopStick();

}

for(int i = 0; i < 4; i++){

philos[i] = new Philosopher(chopSticks[i],chopSticks[(i+1)%4],i);

}

for(int i = 0; i < 4; i++){

philos[i].start();

}

}

}

class Philosopher extends Thread 

{

ChopStick left,right;

int phio_num;

public Philosopher(ChopStick left, ChopStick rightint phio_num)

{

this.left = left;

this.right = right;

this.phio_num = phio_num;

}

public void eat(){

left.takeup();

right.takeup();

System.out.println("哲学家"+(this.phio_num+1)+"在用餐");

}

public void think(){

left.putdown();

right.putdown();

System.out.println("哲学家"+(this.phio_num+1)+"在思考");

}

public void run(){

while(true){

eat();

try

{

sleep(1000);

catch (InterruptedException e)

{

e.printStackTrace();

}

think();

try

{

sleep(1000);

catch (InterruptedException e)

{

e.printStackTrace();

}

}

}

}

 

class ChopStick{

boolean available;

ChopStick(){

available = true;

}

public synchronized void takeup(){

while(!available){

try

{

System.out.println("哲学家等待另一根筷子");

wait();

catch (InterruptedException e)

{

e.printStackTrace();

}

}

available = false;

}

public synchronized void putdown(){

available = true;

notify();

}

}

结果:

哲学家1在用餐

哲学家等待另一根筷子

哲学家3在用餐

哲学家等待另一根筷子

哲学家1在思考

哲学家2在用餐

哲学家4在用餐

哲学家3在思考

哲学家等待另一根筷子

哲学家等待另一根筷子

哲学家1在用餐

......

;