Java -- 线程

1. 创建线程(一)

定义线程类, 继承Thread 并重写run(), run()称为线程体。

单继承限制,尽量少用。
class firstThread extends Thread {    //创建线程类
public void run(){                      //重写run() 
for(int i=0; i<100; i++)  
   System.out.println("Thread --->" + i);  
 }
}

public class main {
 public static void main(String[] args) {  
  firstThread ft = new firstThread();     //生成线程类对象
  ft.start();                             //启动线程  不能直接ft.run()
  for(int i=0; i<100; i++)  
   System.out.println("main --->" + i); 
 
}

 

 创建线程(二)

实现接口Runnable, 并将其对象传入 Thread构造函数,生成Thread对象。

class RunnableImpl implements Runnable  
 public void run() {
  for(int i=0; i<100; i++)  
   System.out.println("Runnable --->" + i);   
 
}

public class main {
 public static void main(String[] args) {  
        //生成一个Runnable接口实现类的对象    
  RunnableImpl ri = new RunnableImpl();
  Thread thread = new Thread(ri); //生成Thread对象,并将ri作为参数。
  thread.start();
  
  for(int i=0; i<100; i++)  
   System.out.println("main --->" + i); 
 
}

两种方法对比:

继承Thread类:   编写简单,不必使用Thread.currentThread(),直接this.getName()即可。 但是不能再继承其他类了。。

实现Runnable接口: 可再继承其他类,可以多线程共享一个目标对象,但是编写略复杂,访问当前线程需要用Thread.currentThread()。

 

2. Join 线程等待

public class Main extends Thread{

	private int i;
	public Main(String name)
	{
		super(name);
	}
	public void run()
	{
		for(; i<100; i++)
		{
			System.out.println(getName() + " " + i);
		}
	}
	
	public static void main(String[] args) throws InterruptedException
	{
		Main thread1 =  new Main("1");
		Main thread2 =  new Main("2");
		
		for(int i=0; i<100; i++)
		{
			if( i==20 )
			{
				thread1.start();
				thread1.join(); //一直阻塞到线程1结束
				thread2.start();				
			}
		}
	}
}

 

3. 后台线程 (守护线程) : JVM垃圾回收线程就是典型的后台线程,如果所有的前台线程都死亡,后台线程会自动死亡。

调用Thread对象的setDaemon(true)则可以设置线程为后台线程。

例如上面的  thread1.setDaemon(true);  即可。。

 

4. 线程让步 和 优先级设置

使用Thread的静态方法  Thread.yield()即可, 让步后线程并不是进入阻塞态,而是进入就绪态 重新竞争。

设置线程优先级可以用 thread1.setPriority(int ...) ; 输入参数可以为 MAX_PRIORITY 值为10, MIN_PRIORITY 1, NORM_PRIORITY 5.

 

5. 同步代码块 synchronized

可以使用同步代码块,锁定临界资源 synchronized(Object obj){... ....}

public void run()
 {
  Integer i;
  for(i=0; i<100; i++)
  { 
   synchronized(i)  //同步代码块
   {
    System.out.println(getName() + " " + i);
   }
  }
 }

还可以用synchronized 修饰类的方法,让该方法变为线程安全。

例如  public synchronized void draw() { ... ... }

 

6. 同步锁    ReadWriteLock(读写锁) ReentrantLock(可重入锁) 

class A
{
	private final ReentrantLock lock = new ReentrantLock();  //定义锁对象
	public void fun() 
	{
		lock.lock();   //加锁
		try
		{
			// 需要 线程安全的代码
		}
		finally
		{
			lock.unlock();  //解锁
		}
	}
}


7.线程通信

利用wait() 当前线程等待   notify()唤醒在同步监视器上等待的单个线程。  notifyAll()唤醒在同步监视器上的所有线程。

class A   //属性 num 加一  减一
{
	private Boolean putflag = false;
	private Integer num = 0;
	
	public synchronized void get()
	{
		try
		{
			if( !putflag )
			{
				wait();   //阻塞
			}
			else
			{				
				num--;
				System.out.println(Thread.currentThread().getName() + " get " + num);
				putflag = false;
				notifyAll();  //唤醒
			}			
		}
		catch (InterruptedException e)
		{
			e.printStackTrace();
		}
	}
	
	public synchronized void put()
	{
		try
		{
			if( putflag )
			{
				wait();
			}
			else
			{				
				num++;
				System.out.println(Thread.currentThread().getName() + " put " + num);
				putflag = true;
				notifyAll();
			}
		}
		catch (InterruptedException e)
		{
			e.printStackTrace();
		}
	}		
}

class Get extends Thread
{
	private A a;
	private String name;
	public Get(String name, A a)
	{
		this.name = name;
		this.a = a;		
	}
	public void run()
	{
		for(int i=0; i<10; i++)
		{
			System.out.println(name);
			a.get();  //减一
		}
	}
}

class Put extends Thread
{
	private A a;
	private String name;
	public Put(String name,A a)
	{
		this.name = name;
		this.a = a;
	}
	public void run()
	{
		for(int i=0; i<10; i++)
		{
			System.out.println(name);
			a.put();  //加一
		}
	}
}


public class Main extends Thread{
		
	public static void main(String[] args)
	{
		A a = new A();
		new Get("lisi", a).start();
		new Put("wangwu", a).start();
		new Put("zhangsan", a).start();		
	}	
}

输出效果是  加一 减一 交替进行。
如果不是用synchronized来保证同步的,如果是用lock, 可以用Condition来做协调

如下只需修改Class A

class B
{
	private final Lock lock = new ReentrantLock();  //定义一个锁 lock
	private final Condition cond = lock.newCondition();  //定义 Condition
	public void put()
	{
		lock.lock();
		try
		{
			if( !flag )
			{
				cond.await();  //阻塞
			}
			else
			{
				.... .....
				cond.signalAll();  //唤醒
			}
		}
	}
	
}

使用管道线程间通信

管道字节流: PiedInputStream PieOutputStream  管道字符流: PipedReader PipedWriter  新IO管道Channel: Pipe.SinkChannel PipeSourceChannel

class ReaderThread extends Thread
{
	private PipedReader pr;       //输入管道
	private BufferedReader br;   
	public ReaderThread(PipedReader pr)
	{
		this.pr = pr;
		this.br = new BufferedReader(pr);
	}
	public void run()
	{
		String buf = null;
		try
		{
			while( (buf=br.readLine()) != null )
			{
				System.out.println("Reader: " + buf);
			}
		}
		catch (IOException e)
		{
			e.printStackTrace();
		}
		finally
		{
			try {
				br.close();
			} catch (IOException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}
	}
}

class WriterThread extends Thread
{
	String[] strs = new String[]{ "1234", "5678", "qwer", "asdf" };
	private PipedWriter pw;  //写管道
	public WriterThread(PipedWriter pw)
	{
		this.pw = pw;		
	}
	public void run()
	{
		try
		{
			for(int i=0; i<10; i++)
			{
				pw.write(strs[i%4] + "\n");
				System.out.println("Writer" + strs[i%4]);
			}
		}
		catch(IOException e)
		{
			e.printStackTrace();
		}
		finally
		{
			try {
				pw.close();
			} catch (IOException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}
	}
	
}

public class Main extends Thread{
		
	public static void main(String[] args)
	{
		PipedReader pr = null;
		PipedWriter pw = null;
		try
		{
			pw = new PipedWriter();
			pr = new PipedReader();
			pw.connect(pr);           //管道连接
			new WriterThread(pw).start();   //开启读写线程
			new ReaderThread(pr).start();
		}
		catch(IOException e)
		{
			e.printStackTrace();
		}
	}	
}



 

 
 

 

posted @ 2013-11-06 10:27  今晚打酱油_  阅读(158)  评论(0编辑  收藏  举报