`
fehly
  • 浏览: 245389 次
  • 性别: Icon_minigender_1
  • 来自: 上海
社区版块
存档分类
最新评论

线 程

    博客分类:
  • java
阅读更多

线 程

线程是一个程序内部的顺序控制流

线程和进程

  • 每个进程都有独立的代码和数据空间,进程切换的开销大
  • 线程:轻量的进程,同一类线程共享代码和数据空间,每个线程有独立的运行栈和程序计数器(pc),线程切换的开销小.
  • 多进程:在操作系统中能同时运行多个任务(程序);
  • 多线程:在同一应用程序中有多个顺序流同时执行.

线程的概念模型

  • 虚拟的cpu,由java.lang.Thread类封装和虚拟;
  • cpu所执行的代码,传递给Thread类对象;
  • cpu所处理的数据,传递给Thread类对象

创建线程

java的线程是通过java.lang.Thread类实现的.

每个线程都是通过某个特定Thread对象所对应的方法run()来完成其操作的,方法run()称为线程体。

public class TestThread1 {
	public static void main(String args[]) {
		Runner1 r = new Runner1();
		Thread t = new Thread(r);
		t.start();
	}
}

class Runner1 implements Runnable {
	public void run() {
		for(int i=0; i<30; i++) {	
			System.out.println("No. " + i);
		}
	}
}

多线程

java中引入线程机制的目的在于实现多线程(Multi-Thread)

public class TestThread2 {
	public static void main(String args[]) {
		Runner2 r = new Runner2();
		Thread t1 = new Thread(r);
		Thread t2 = new Thread(r);
		t1.start();
		t2.start();
	}
}

class Runner2 implements Runnable {
	public void run() {
		for(int i=0; i<20; i++) {
			String s = Thread.currentThread().getName();
			System.out.println(s + ": " + i);
		}
	}
}

创建线程第二种方式

直接继承Thread类创建线程

public class TestThread3 {	
	public static void main(String args[]){
		Thread t = new Runner3();
		t.start();
    }
}
class Runner3 extends Thread {
	public void run() {
		for(int i=0; i<30; i++) {	
			System.out.println("No. " + i);
		}
	}
}

两种方式的比较

一.使用Runnable接口创建线程:

  • 可以将cpu,代码和数据分开,形成清晰的模型;
  • 线程体run()方法所在的类还可以从其他类继承一些有用的属性或方法;
  • 并有利于保持程序风格的一致性.

 二.直接继承Thread类创建线程:

  • Thread子类无法再从其他类继承
  • 编写简单,run()方法的当前对象就是线程对象,可直接操纵.

后台线程

相关基本概念:

  • 后台处理(Background Processing)
  • 后台线程(Background Thread/Daemon Thread)
  • 用户线程(User Thread)
  • 主线程(Main Thread)
  • 子线程(Sub Thread)

Thread类提供的相关方法:

  • public final boolean isDaemon()
  • public final void setDaemon(Boolean on)
public class TestDaemonThread {	
	public static void main(String args[]){
		Thread t1 = new MyRunner(10);
		t1.setName("用户线程t1");
		t1.start();
		
		Thread t2 = new MyRunner(100);
		t2.setDaemon(true);
		t2.setName("后台线程t2");
		t2.start();
		
		for(int i=0;i<10;i++){
			System.out.println(Thread.currentThread().getName() + ": " + i);	
		}
		System.out.println("主线程结束!");
    }
}

class MyRunner extends Thread {
	private int n;
	public MyRunner(int n){
		this.n = n;	
	}
	public void run() {
		for(int i=0; i<n; i++) {	
				System.out.println(this.getName() + ": " + i);
		}
		System.out.println(this.getName() + "结束!");
	}
}

线程的生命周期

  • 新建状态
  • 就绪状态
  • 运行状态
  • 阻塞状态
  • 终止状态

线程优先级

线程的优先级用数字来表示,范围从1到10.

主线程的缺省优先级是5,子线程的优先级默认与其父线程相同.

Thread类提供的相关方法:

  • public final int getPriority()
  • public final void setPriority(int newPriority)

相关静态整型常量:

  • Thread.MIN_PRIORITY=1
  • Thread.MAX_PRIORITY=10
  • Thread.NORM_PRIORITY=5
public class TestPriority {	
	public static void main(String args[]){
		System.out.println("线程名\t优先级");
		Thread current = Thread.currentThread();
		System.out.print(current.getName() + "\t");
		System.out.println(current.getPriority());		
		Thread t1 = new Runner();
		Thread t2 = new Runner();
		Thread t3 = new Runner();
		t1.setName("First");		
		t2.setName("Second");		
		t3.setName("Third");		
		t2.setPriority(Thread.MAX_PRIORITY);
		t3.setPriority(8);
       	t1.start();
		t2.start();
       	t3.start();
    }
}

class Runner extends Thread {
	public void run() {
		System.out.print(this.getName() + "\t");
		System.out.println(this.getPriority());		
	}
}

线程串行化 

在多线程程序中,如果在一个线程运行的过程中药用到另一个线程的运行结果,则可进行线程的串型化处理.

Thread类提供的相关方法:

  • public final void join()
  • public final void join(long millis)
  • public final void join(long millis,int nanos)
public class TestJoin {	
	public static void main(String args[]){
		MyRunner r = new MyRunner();
		Thread t = new Thread(r);
		t.start();
		try{
			t.join();
		}catch(InterruptedException e){
			e.printStackTrace();
		}
		for(int i=0;i<50;i++){
			System.out.println("主线程:" + i);
		}
    }
}

class MyRunner implements Runnable {
	public void run() {
		for(int i=0;i<50;i++) {
			System.out.println("SubThread: " + i);
		}
	}
}

 线程休眠

线程休眠——暂停执行当前运行中的线程,使之进入阻塞状态,待经过指定的"延迟时间"后再醒来并转入到就绪状态.

Thread类提供的相关方法:

  • public static void sleep(long millis)
  • public static void sleep(long millis,int nanos)
import java.awt.Color;
import java.util.Calendar;
import java.util.GregorianCalendar;
import javax.swing.*;

public class DigitalClock{
	public static void main(String[] args){
		JFrame jf = new JFrame("Clock");
		JLabel clock = new JLabel("Clock");
		clock.setHorizontalAlignment(JLabel.CENTER);
		jf.add(clock,"Center");
		jf.setSize(140,80);
		jf.setLocation(500,300);
		jf.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		jf.setVisible(true);
		
		Thread t = new MyThread(clock);
		t.start();
	}	
}

class MyThread extends Thread{
	private JLabel clock;
	public MyThread(JLabel clock){
		this.clock = clock;
	}
	public void run(){
		while(true){
			clock.setText(this.getTime());
			try{
				Thread.sleep(1000); //this.sleep(1000);	
			}catch(InterruptedException e){
				e.printStackTrace();	
			}	
		}	
	}
	public String getTime(){
		Calendar c = new GregorianCalendar();
		String time = c.get(Calendar.YEAR) + "-" +
					  (c.get(Calendar.MONTH) + 1) + "-" +
					  c.get(Calendar.DATE)  + "  " ;
		int h = c.get(Calendar.HOUR_OF_DAY);
		int m = c.get(Calendar.MINUTE);
		int s = c.get(Calendar.SECOND);
		String ph = h<10 ? "0":"";
		String pm = m<10 ? "0":"";
		String ps = s<10 ? "0":"";		
		time += ph + h + ":" + pm + m + ":" + ps + s; 
		return time;
	}	
}

 线程让步

线程——让运行中的线程主动放弃当前获得的CPU处理机会,但不是该线程阻塞,而是使之转入就绪状态.

Thread类提供的相关方法:

  • public static void yield()
import java.util.Date;

public class TestYield{
	public static void main(String[] args){
		Thread t1 = new MyThread(false);
		Thread t2 = new MyThread(true);
		Thread t3 = new MyThread(false);
		t1.start();
		t2.start();
		t3.start();
	}	
}

class MyThread extends Thread{
	private boolean flag;
	public MyThread(boolean flag){
		this.flag = flag;
	}
	public void setFlag(boolean flag){
		this.flag = flag;
	}
	public void run(){
		long start = new Date().getTime();
		for(int i=0;i<500;i++){
			if(flag)
				Thread.yield();
			System.out.print(this.getName() + ": " + i + "\t");
		}
		long end = new Date().getTime();
		System.out.println("\n" + this.getName() + "执行时间: " + (end - start) + "毫秒");
	}
}

 线程挂起和恢复

线程挂起——暂时停止当前运行中的线程,使之转入阻塞状态,并且不会自动恢复运行.

线程恢复——使得一个已挂起的线程恢复运行.

Thread类提供的相关方法:

  • public final void suspend()
  • public final void resume()

利用线程挂起/恢复机制实现倒计时器

import java.awt.Color;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.Date;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JButton;

public class TestSuspend{
	public static void main(String[] args){
		JFrame jf = new JFrame("Timer");
		JButton pause = new JButton("Pause");
		JLabel clock = new JLabel("Timer");
		clock.setBackground(Color.GREEN);
		clock.setOpaque(true);
		clock.setHorizontalAlignment(JLabel.CENTER);
		jf.add(clock,"Center");
		jf.add(pause,"North");
		jf.setSize(140,80);
		jf.setLocation(500,300);
		jf.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		jf.setVisible(true);

		MyThread mt = new MyThread(clock,10000);
		mt.start();
		MyListener ml = new MyListener(clock,mt);
		pause.addActionListener(ml);
	}	
}

class MyThread extends Thread{
	private JLabel clock;
	private long time;
	private long end;
	
	public MyThread(JLabel clock,long time){
		this.clock = clock;	
		this.time = time;
	}
	public void init(){
		long start = new Date().getTime();
		end = start + time;
	}	
	public void run(){
		this.init();
		while(true){
			long now = new Date().getTime();
			time = end - now;
			if(time > 0){
				String s = this.convert(time);	
				clock.setText(s);
			}else{
				break;	
			}
			try{
				Thread.sleep(10);	
			}catch(InterruptedException e){
				e.printStackTrace();	
			}
		}
		clock.setText("时间到!");	
		clock.setBackground(Color.RED);
	}	
	public String convert(long time){
		long h = time / 3600000;
		long m = (time % 3600000) / 60000;
		long s = (time % 60000) / 1000;
		long ms = (time % 1000) / 10;
		String ph = h<10 ? "0":"";
		String pm = m<10 ? "0":"";
		String ps = s<10 ? "0":"";	
		String pms = ms<10 ? "0":"";	
		String txt = ph + h + ":" + pm + m + ":" + ps + s + "." + pms + ms; 
		return txt;
	}	
}

class MyListener implements ActionListener{
	private JLabel clock;
	private MyThread mt;
	private boolean running= true;
	
	public MyListener(JLabel clock,MyThread mt){
		this.clock = clock;
		this.mt = mt;
	}	
	public void actionPerformed(ActionEvent e){
		if(!mt.isAlive())
			return;
		JButton jb = (JButton)(e.getSource());
		if(running){
			jb.setText("Replay");
			clock.setBackground(Color.YELLOW);
			mt.suspend();
		}else{
			jb.setText("Pause");
			clock.setBackground(Color.green);
			mt.init();
			mt.resume();
		}
		running = !running;
	}	
}

线程控制基本方法

isAllve()               判断线程是否还"活"着,即线程是否还未终止
getPriority()         获得线程的优先级数值
setPriority()         设置线程的优先级数值
sleep()                 将当前线程睡眠指定毫秒数
join()                    调用某线程的该方法,将当前线程与该线程"合并",即等待该线程结束,再恢复当前线程的运行.
yield()                  让出cpu,当前线程进入就绪队列等待调度
suspend()/resume() 挂起和恢复线程
wait()                   当前线程进入对象的wait pool
notify()和notifyAll()  唤醒对象的wait pool中的一个/所有等待线程

 互斥锁

  • 在java语言中,引入了对象互斥锁的概念,来保证共享数据操作的完整性.
  • 每个对象都对应于一个可称为"互斥锁"的标记,这个标记用来保证在任意时刻,只能有一个线程访问该对象.
  • 关键字synchronized来与对象的互斥锁联系,当某个对象用synchronized修饰时,表明该对象在任意时刻只能由一个线程访问.

synchronized用法

用于方法声明中,标明整个方法为同步方法

public synchronized void push(char c){
       data[idx] = c;
        idx++;
}
public char pop(){
//其他代码
   synchronized(this){
           idx--;
           return data[idx];
  }
   //其他代码
}

线程死锁

并发运行的多个线程间彼此等待,都无法运行的状态称为线程死锁.

public class TestDeadLock{
	public static void main(String args[]){
		StringBuffer sb = new StringBuffer("ABCD");
		MyThread t = new MyThread(sb);
		t.start();	
		synchronized(sb){
			try{
				t.join();
			}catch(InterruptedException e){
				e.printStackTrace();	
			}
			System.out.println(sb);	
		}
		System.out.println("Main thread is over!");	
	}	
}

class MyThread extends Thread{
	private StringBuffer sb;
	public MyThread(StringBuffer sb){
		this.sb = sb;
	}
	public void run(){
		synchronized(sb){
			sb.reverse();
		}
		System.out.println("Sub thread is over!");	
	}	
}

 ---------------------------------------------------------------------------------------------------------------------------------

public class TestDeadLock2{
	public static void main(String args[]){
		char[] a = {'A','B','C'};
		char[] b = {'D','E','F'};
		MyThread t1 = new MyThread(a,b);
		MyThread t2 = new MyThread(b,a);
		t1.start();
		t2.start();		
	}	
}

class MyThread extends Thread{
	private char[] source;
	private char[] dest;
	
	public MyThread(char[] source,char[] dest){
		this.source = source;
		this.dest = dest;
	}
	public void run(){
		synchronized(source){
			try{
				Thread.sleep(1000);
			}catch(InterruptedException e){
				e.printStackTrace();	
			}
			
			synchronized(dest){
				System.arraycopy(source,0,dest,0,source.length);
				System.out.println(dest);
			}		
		}
	}	
}

线程同步通信

为避免死锁,在线程进入阻塞状态时应尽量释放其锁定的资源,以为其他的线程提供运行的机会.

相关方法:

  • public final void wait()
  • public final void notify()
  • public final void notfyAll()

生产者——消费者问题

public class SyncStack{  //支持多线程同步操作的堆栈的实现
	private int index = 0;
	private char []data = new char[6];	
	public synchronized void push(char c){
		while(index == data.length){
		try{
				this.wait();
			}catch(InterruptedException e){}
			}
		this.notify();
		data[index] = c;
		index++;
		System.out.println("produced:"+c);
	}
	public synchronized char pop(){
		while(index ==0){
			try{
				this.wait();
			}catch(InterruptedException e){}
			    	}
		this.notify();
		index--;
		System.out.println("消费:"+data[index]);
		return data[index];
	}
}

 

public class SyncTest{
    public static void main(String args[]){
		SyncStack stack = new SyncStack();
		Runnable p=new Producer(stack);
		Runnable c = new Consumer(stack);
		Thread t1 = new Thread(p);
		Thread t2 = new Thread(c);
		t1.start();
		t2.start();
    }
}


class  Producer implements Runnable{
	SyncStack stack;	
	public Producer(SyncStack s){
		stack = s;
	}
	public void run(){
		for(int i=0; i<20; i++){
			char c =(char)(Math.random()*26+'A');
			stack.push(c);
			try{							        
				Thread.sleep((int)(Math.random()*300));
			}catch(InterruptedException e){
			}
		}
	}
}

class Consumer implements Runnable{
	SyncStack stack;	
	public Consumer(SyncStack s){
		stack = s;
	}
	public void run(){
		for(int i=0;i<20;i++){
			char c = stack.pop();
			try{							           
				Thread.sleep((int)(Math.random()*500));
			}catch(InterruptedException e){
			}
		}
	}
}

线程间数据传输

使用管道流实现线程间数据传输

import java.io.*;
public class Test{
	public static void main(String args[]){
		PipedInputStream pin = new PipedInputStream();
		PipedOutputStream pout = new PipedOutputStream();
		try{
			pin.connect(pout);
		}catch(IOException e){
			e.printStackTrace();
		}
		Thread t1 = new Sender(pout);
		Thread t2 = new Receiver(pin);
		t1.start();
		t2.start();	
	}		
}

class Sender extends Thread{
	private DataOutputStream dos;
	public Sender(PipedOutputStream p){
		dos = new DataOutputStream(p);	
	}
	public void run(){
		try{
			dos.writeUTF("HelloWorld");
			dos.close();
		}catch(IOException e){
			e.printStackTrace();	
		}
	}
}

class Receiver extends Thread{
	private DataInputStream dis;
	public Receiver(PipedInputStream p){
		dis = new DataInputStream(p);	
	}
	public void run(){
		try{
			System.out.println(dis.readUTF());
			dis.close();
		}catch(IOException e){
			e.printStackTrace();	
		}
	}		
}

类的同步性与线程安全

验证同步类的线程安全性

import java.util.Vector;
public class Test{
	public static void main(String args[]){
		Vector<String> v = new Vector<String>();
		v.addElement("Tom");	
		v.addElement("Billy");	
		v.addElement("Kessy");	
		v.addElement("Mr Brown");
		v.addElement("Kity");	
		v.addElement("Johnson");	
		v.addElement("Nancy");	
		v.addElement("Scott");
		v.addElement("Ruby");	
		MyThread1 mt1 = new MyThread1(v);
		MyThread2 mt2 = new MyThread2(v);
		mt1.start();
		mt2.start();		
	}		
}

class MyThread1 extends Thread{
	private Vector<String> v;
	public MyThread1(Vector<String> v){
		this.v = v;	
	}
	public void run(){
		synchronized(v){
			int total = v.size();
			for(int i=0;i<total;i++){
				String s = v.elementAt(i);
				StringBuffer sb = new StringBuffer(s);
				s = sb.reverse().toString();
				v.setElementAt(s,i);
				System.out.println(v.elementAt(i));	
			}
		}
	}
}

class MyThread2 extends Thread{
	private Vector<String> v;
	public MyThread2(Vector<String> v){
		this.v = v;	
	}
	public void run(){
		v.clear();
	}
}

 定时器

使用定时器实现数字时钟功能

import javax.swing.JFrame;
import javax.swing.JLabel;
import java.util.Timer;
import java.util.TimerTask;
import java.util.Calendar;
import java.util.GregorianCalendar;

public class TestTimer{
	public static void main(String args[]){
		JFrame jf = new JFrame("Clock");
		JLabel clock = new JLabel("Clock");
		clock.setHorizontalAlignment(JLabel.CENTER);
		jf.add(clock,"Center");
		jf.setSize(140,80);
		jf.setLocation(500,300);
		jf.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		jf.setVisible(true);
		Timer t = new Timer();
		TimerTask tt = new MyTask(clock);	
		t.schedule(tt,0,1000);
	}		
}

class MyTask extends TimerTask{
	private JLabel clock;
	public MyTask(JLabel clock){
		this.clock = clock;	
	}
	public void run(){
		clock.setText(this.getTime());
	}
	public String getTime(){
		Calendar c = new GregorianCalendar();
		String time = 	c.get(Calendar.YEAR) + "-" +
					(c.get(Calendar.MONTH) + 1) + "-" +
					c.get(Calendar.DATE)  + "  " ;
		int h = c.get(Calendar.HOUR_OF_DAY);
		int m = c.get(Calendar.MINUTE);
		int s = c.get(Calendar.SECOND);
		String ph = h<10 ? "0":"";
		String pm = m<10 ? "0":"";
		String ps = s<10 ? "0":"";		
		time += ph + h + ":" + pm + m + ":" + ps + s; 
		return time;
	}
}

 

分享到:
评论
1 楼 tianzhuowan 2011-02-16  
写的很清晰和简单,相当好,辛苦了lz!

相关推荐

Global site tag (gtag.js) - Google Analytics