`

Java 线程

 
阅读更多
1.线程的基本概念

线程是一个程序里面不同的执行路径
在同一个时间点,一个cpu只能有一个线程在执行。

2.线程的创建与启动
第一种更好,因为一个类只能集成一个父类,而可以实现很多接口


第一种
定义线程实现Runnable接口

package com.anker.thread;
public class TestThread1 {
	public static void main(String args[]) {
		Runner1 r = new Runner1();
//		r.run(); 直接调用等于方法调用,而非新启线程
		 Thread t = new Thread(r);
		 t.start();
		for (int i = 0; i < 100; i++) {
			System.out.println("Main Thread:" + i);
		}
	}
}
class Runner1 implements Runnable {
	@Override
	public void run() {
		for (int i = 0; i < 100; i++) {
			System.out.println("Runner1:" + i);
		}
	}
}
第二种
集成Thread
package com.anker.thread;

public class TestThread2 {

	public static void main(String args[]) {
		Runner2 r = new Runner2();
		r.start();
		for (int i = 0; i < 100; i++) {
			System.out.println("Main Thread:" + i);
		}
	}
}
class Runner2 extends Thread {
	@Override
	public void run() {
		for (int i = 0; i < 100; i++) {
			System.out.println("Runner1:" + i);
		}
	}
}

线程的状态:

start->就绪状态->运行状态->->终止

运行状态中会存在以下状态:
阻塞状态:sychronized同步块,需要等待对象锁或类锁
waiting: 调用object.wait,将当前线程处于等待状态,并将对象锁释放,等待notify或者notifyAll()唤醒。
注意:使用notify,在众多等待同一个锁的任务中只有一个被唤醒,而使用notifyAll唤醒的是等待同一个锁的所有任务。

注意是等待同一个锁。
sleep:Thread.sleep(),将当前线程处于sleep状态,但仍持有线程资源。
interrupt: 外部通过interrupt方法,将从sleep状态中唤醒。

线程的方法:
isAlive:线程是否终止
getPriority(): 获得线程的优先级
setPriority(): 设置线程的优先级(每个线程有自己的优先级,优先级越高的获得的cpu时间越多)
Thread.sleep(): 将当前线程睡眠指定毫秒数,但仍然持有线程资源
Thread.interrupt(); //中断线程, 此方法适用于将线程从sleep状态中唤醒。
public boolean Thread.isInterrupted() //判断是否中断
public static boolean Thread.interrupted() //判断是否中断,并清除当前中断状态。

join(): 调用某线程的该方法,将当前线程与该线程"合并",即等待该线程结束,再
恢复当前线程的运行
join的本质是
while(isAlive())
{
 wait(0);
}
待线程执行完毕后,系统会调用notifyAll()。因此不建议在Thread实例中使用wait和notify()方法。有可能影响到API的调用。

yield(): 让出cpu,当前线程进入就绪队列等待调度(只是下一次的执行机会让给其他线程)
wait(): 当前线程进入对象的wait pool,与sleep不同,sleep在休眠过程的时候仍然持有锁,而wait会释放锁,
直到其他线程唤醒。
notify()/notifyAll():唤醒对象的wait pool中的一个/所有等待线程


挂起(suspend) 和继续执行(resume)线程,不建议使用此两个函数
--suspend 不会释放锁
--如果加锁在resume()之前,则发生死锁。

Thread.stop()不推荐使用,它会释所有monitor。


重新的方法不能抛出跟父类方法不同的异常

3.线程的调度和优先级
java提供一个线程调度器来监控程序中启动进入就绪状态的所有线程,
线程调度器按照线程的优先级决定调度那个进程来执行(优先级高的获得更多的cpu执行时间)

线程的优先级用数字来表示,范围从1到10,一个线程的缺省优先级是5
Thread.MIN_PRIORITY=1
Thread.MAX_PRIORITY=10
Thread.MNORM_PRIORITY=5

使用下述方法获得或设置对象的优先级
int getPriority();
void setPriority(int newPriority);



--Interrupt中断线程示例
--Interrupt方法是中断线程的一种优雅方式
public class Test implements Runnable{
	public static void main(String args[]) {
		Test r = new Test();
		Thread t1 = new Thread(r);
		t1.start();				
		for(int j=0;j<100;j++){
			System.out.println("j:"+j);
		}
		t1.interrupt();
}

//	public void run() {
//		while(true){
//			if(Thread.currentThread().isInterrupted()){ //检测是否中断
//				System.out.println("thead is interrupt");
//				break;
//			}
//			try {
//				System.out.println("sleep");
//				Thread.sleep(100000);
//			} catch (InterruptedException e) {
//				// TODO Auto-generated catch block
//				System.out.println("interrupted when Sleep");
////				Thread.currentThread().interrupt();//设置中断状态,抛出异常后会自动清除中断标记位
//			}
//		}		
//		
//	}
	public void run() {
		while (true) {
			if (Thread.currentThread().isInterrupted()) {//判断当前线程是否发生中断,若是则break;
				System.out.println("thead is interrupt");
				break;
			}			
		}
	}


--Join示例
//结果:打印完i之后,再打印j
//join方式是将线程合并到主线程,待线程之后完之后,才会继续执行主线程的逻辑。
public static void main(String args[]) {
		Test1 r = new Test1();
		Thread t1 = new Thread(r);
		t1.start();		
		
		try {
			t1.join();
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
		for(int j=0;j<100;j++){
			System.out.println("j:"+j);
		}
}
	public void run() {
		for(int i=0;i<100;i++){
			System.out.println("i:"+i);
		}
	}




线程同步
所有同步的状态都要考虑加synchronized方法
在Java语言中,引入对象互斥锁的概念,保证共享数据操作的完整性,每个对象对应于
一个可称为"互斥锁"的标记,这个标记保证在任一时刻,只能有一个线程访问该对象。
当对象调用其任意synchronized方法的时候,此对象都被加锁,
这时该对象上的其他synchronized方法只有等到前一个方法调用完毕并释放了锁之后才被调用。
synchronized(xxx),指锁定xxx对象,只能有一个线程访问xxx对象,不相同的对象,是可以同步访问。
当关键字synchronized修饰方法时,是指锁定当前调用对象,等同于synchronized(this){}


–1. 指定加锁对象:对给定对象加锁,进入同步代码前要获得给定对象的锁。

public void run() {
for(int j=0;j<10000000;j++){
 synchronized(instance){
 i++;
}
}
–2. 直接作用于实例方法:相当于对当前实例加锁,进入同步代码前要获得当前实例的锁。等同于方法1的synchronized(this){...代码块..}
public synchronized void increase(){
i++;
}
–3. 直接作用于静态方法:相当于对当前类加锁,进入同步代码前要获得当前类的锁,即使不同的对象访问此段代码,也要依次访问。
public static synchronized void increase(){
i++;
}


package com.anker.thread;

public class TT implements Runnable{	
	int b = 100;
	public synchronized void m1() throws Exception {
		System.out.println("执行m1方法");
		b = 1000;
		Thread.sleep(5000);
		System.out.println("b= "+b);
	}
	public synchronized void m2() throws Exception{
		System.out.println("执行m2方法");
		Thread.sleep(2500);
		b=2000;
		System.out.println("b:"+b);
	}
	@Override
	public void run() {
		try {
			System.out.println("执行run方法");
			m1();
		} catch (Exception e) {
			e.printStackTrace();
		}	
	}
	public static void main(String args[]) throws Exception{
		TT tt = new TT();
		Thread t = new Thread(tt);
		t.start();
		tt.m2();
		System.out.println(tt.b);
	}
}

--在static方法上增加synchronized,即意味着持有类锁,不同的对象仍要依次访问。
//结果为20000000

public class AccountingSyncClass implements Runnable{
	static int i=0;
	public static synchronized void increase(){
		i++;
	}
	public void run() {
		for(int j=0;j<10000000;j++){
			increase();
		}
	}
	public static void main(String[] args) throws InterruptedException {
		Thread t1=new Thread(new AccountingSyncClass());
		Thread t2=new Thread(new AccountingSyncClass());
		t1.start();t2.start();
		t1.join();t2.join();
		System.out.println(i);
	}
}




// wait() 必须在synchronized 函数或者代码块里面
// wait()会让已经获得synchronized 函数或者代码块控制权的Thread暂时休息,并且丧失控制权
// 这个时候,由于该线程丧失控制权并且进入等待,其他线程就能取得控制权,并且在适当情况下调用notifyAll()来唤醒wait()的线程。
// 需要注意的是,被唤醒的线程由于已经丧失了控制权,所以需要等待唤醒它的线程结束操作,从而才能重新获得控制权。
// 所以wait()的确是马上让当前线程丧失控制权,其他的线程可以乘虚而入。
// 所以wait()的使用,必须存在2个以上线程,而且必须在不同的条件下唤醒wait()中的线程。
// 当存在多个等待线程时, notify是随机选择等待的线程进行唤醒。
//结果打印顺序
T1 start! 
T1 wait for object 
T2 start! notify one thread
T2 end!
T1 end!


public class TestWait {
	final static Object object = new Object();
	public static class T1 extends Thread{
        public void run()
        {
            synchronized (object) {
                System.out.println(System.currentTimeMillis()+":T1 start! ");
                try {
                	System.out.println(System.currentTimeMillis()+":T1 wait for object ");
                	object.wait();		//如果当前线程不是锁的持有者,该方法抛出一个IllegalMonitorStateException异常。这里需要采用锁对象的的对象
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println(System.currentTimeMillis()+":T1 end!");
            }
        }
	}
	public static class T2 extends Thread{
        public void run()
        {
            synchronized (object) {
                System.out.println(System.currentTimeMillis()+":T2 start! notify one thread");
                object.notify();
                System.out.println(System.currentTimeMillis()+":T2 end!");
                try {
					Thread.sleep(2000);
				} catch (InterruptedException e) {
				}
            }
        }
	}
	public static void main(String[] args) {
        Thread t1 = new T1() ;
        Thread t2 = new T2() ;
//        Thread t1_1 = new T1() ;
//        t1_1.start();
        t1.start();
        t2.start();
	}
} 


消费者与生产者的故事

package com.anker.thread;

public class ProducerConsumer {
	public static void main(String args[]){
		SynStack ss = new SynStack();
		Producer p = new Producer(ss);
		Consumer c = new Consumer(ss);
		new Thread(p).start();
		new Thread(c).start();
	}
}
class WoTou{
	int id;
	WoTou(int id){
		this.id = id;
	}
	public String toString(){
		return "WoTou:"+id;
	}
}
class SynStack{
	int index = 0;
	WoTou[] arrWT = new WoTou[6];
	public synchronized void push(WoTou wt){
		while(index == arrWT.length){//使用while会确保线程被打断时,仍然要执行判断
			try {
				System.out.println("push wait方法被调用");
				this.wait();//只能在同步控制方法或同步块中调用wait()、notify()和notifyAll()。如果在非同步的方法里调用这些方法抛出异常
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		}
		this.notify();
		arrWT[index] = wt;
		System.out.println("push WoTou index:"+index);
		index ++;		
	}
	public synchronized WoTou pop(){
		while(index == 0){
			try {
				System.out.println("pop wait方法被调用");
				this.wait();
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		}
		this.notify();		
		index --;
		System.out.println("pop WoTou index:"+index);
		return arrWT[index];
	}	
}
class Producer implements Runnable{
	SynStack ss = null;
	Producer(SynStack ss){
		this.ss = ss;
	}
	@Override
	public void run() {
		for(int i=0;i<20;i++){
			WoTou wt= new WoTou(i);		
			ss.push(wt);
//			System.out.println("WtTou is produced:"+wt);
			try{
				Thread.sleep((int)(Math.random() * 1000));
			}catch (InterruptedException e) {
				e.printStackTrace();
			}
		}		
	}	
}
class Consumer implements Runnable{
	SynStack ss = null;
	Consumer(SynStack ss){
		this.ss = ss;
	}
	@Override
	public void run() {
		for(int i=0;i<20;i++){
			WoTou wt= ss.pop();
//			System.out.println("WtTou is consumer:"+wt);
			try{
				Thread.sleep((int)(Math.random() * 1000));
			}catch (InterruptedException e) {
				e.printStackTrace();
			}
		}		
	}	
}
 

 

分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics