java线程详解_JAVA_编程开发_程序员俱乐部

中国优秀的程序员网站程序员频道CXYCLUB技术地图
热搜:
更多>>
 
您所在的位置: 程序员俱乐部 > 编程开发 > JAVA > java线程详解

java线程详解

 2015/4/23 1:04:06  hm4123660  程序员俱乐部  我要评论(0)
  • 摘要:程序本身是一个静态的概念,而进程是程序的一次执行过程,每一个进程都有自己的地址空间。线程实际上是在进程的基础之上的进一步划分。一个进程至少对应一个线程,线程之间共享一个内存空间,线程之间可以相互切换,并发执行。一.线程的实现java中实现线程有两种方式:1.继承Thread类2.实现Runnable接口(这种方式用得比较多)继承Thread类实现代码:publicclassTest{publicstaticvoidmain(String[]args)
  • 标签:详解 Java 线程

?????????程序本身是一个静态的概念,而进程是程序的一次执行过程,每一个进程都有自己的地址空间。线程实际上是在进程的基础之上的进一步划分。一个进程至少对应一个线程,线程之间共享一个内存空间,线程之间可以相互切换,并发执行。

?

一.线程的实现

??????java中实现线程有两种方式:

1.继承Thread类

2.实现Runnable接口(这种方式用得比较多)

?

继承Thread类实现代码:

?

class="java">public class Test {

	public static void main(String[] args){

		myThread thread=new myThread();
		//不是马上执行线程,而是把线程置于就绪状态,等待CPU调用
		thread.start();
	    
	}

}
//继承Thread类
class myThread extends Thread{
	@Override
	public void run() {
		int i=0;
		while(true)
		{
			if(i>10)
				break;
			System.out.println(i);
			i++;
		}
	}
	
}

?

?

实现Runnable接口代码:

?

public class Test {

	public static void main(String[] args){

		myRunnable runnable=new myRunnable();
		
		Thread thread=new Thread(runnable);
		
		//不是马上执行线程,而是把线程置于就绪状态,等待CPU调用
		thread.start();
	    
	}

}
//继承Thread类
class myRunnable implements Runnable{	
	public void run() {
		int i=0;
		while(true)
		{
			if(i>10)
				break;
			System.out.println(i);
			i++;
		}
	}
	
}

?

?

?

Runnale是实现run方法,Thread是重写run方法,run方法是Runnable接口的一个抽象方法,Thread类已经实现了该接口。

run方法执行完线程会正常结束

?

二.线程主要方法

1.sleep方法

???? 让当前线程进入休眠状态,让出当前执行CPU的时间,该线程不会丢失任何监视器的所属权,调用方法为Thread.sleep(1000)//休眠一秒。sleep方法休眠完成后,线程会进入就绪状态,参与CPU的争抢。

????有时会看到线程调用sleep(0),表示释放cpu时间,马上回到就绪状态争抢cpu使用权。sleep(0)可以释放当前线程执行完所剩的时间(如果有剩余的话)。这样可以让去其他线程得到执行,不会浪费所剩下的时间。提高效率。

示例代码:

?

class myRunnable implements Runnable {
	public void run() {
		int i = 0;

		try {
			while (true) {
				if (i > 10)
					break;
				System.out.println(i);
				i++;
				Thread.sleep(1000);//休眠一秒
			}
		} catch (InterruptedException e) {
			e.printStackTrace();
		}

	}

}

?

?

2.join方法

?????把指定线程加入到当前线程,可以将两个交替执行的线程合并为顺序执行。如,在线程1中调用了线程2的join()方法,直到线程2执行完,才会继续执行线程1。

join方法调用形式:

1.join()?? //直到调用线程执行结束

2.join(int millis)? //等待调用线程指定时间

?

示例代码:

?

public class Test {

	public static void main(String[] args) {

		myRunnable runnable = new myRunnable();

		Thread thread = new Thread(runnable);

		// 不是马上执行线程,而是把线程置于就绪状态,等待CPU调用
		thread.start();

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

			try {
				if (i == 4)
					thread.join();//会等待子线程执行完毕在继续执行
				System.out.println("主线程: "+i);
				
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		}

	}

}
//继承Thread类
class myRunnable implements Runnable {
	public void run() {
		int i = 0;

		try {
			while (true) {
				if (i > 10)
					break;
				System.out.println("子线程: "+i);
				i++;
				Thread.sleep(1000);//休眠一秒
			}
		} catch (InterruptedException e) {
			e.printStackTrace();
		}

	}

}

?

?

3.interrupt方法

????? 中断线程。其实真正中断线程是线程内部自己实现的,可以把interrupt理解为一个中断标记,告诉线程内部实现中断,当然有可能会中断失败。如果在调用interrupt方法打上中断标记后,又调用了wait(),join(),sleep()方法,此时会清除interrupt的中断标记,并抛出InterruptedException异常

?

其实不推荐使用interrupt方法来中断线程,建议使用自己定义的标记来中断线程。

如:

?

// 继承Thread类
class myRunnable implements Runnable {
	
	private boolean flag=true;//线程标记
		
	public boolean isFlag() {
		return flag;
	}

	public void setFlag(boolean flag) {
		this.flag = flag;
	}

	public void run() {
		
		while(flag){
			int i = 0;
			try {
				while (true) {
					
					System.out.println("子线程: "+i);
					i++;
					Thread.sleep(1000);//休眠一秒
				}
			} catch (InterruptedException e) {
				e.printStackTrace();
			}

		}
	}
}

?

?

?

?当需要终止线程时,调用setFlag(false)就可以了。此时run方法将会执行完毕,线程正常结束。

?

4.yield()方法

?

??? 让出此次cpu的执行权力,直接进入就绪状态,等待争抢下一次CPU使用权

?

yield()和sleep()的区别:

1.sleep()使当前线程进入停滞状态,所以执行sleep()的线程在指定的时间内肯定不会执行;yield()只是使当前线程重新回到可执行状态,所以执行yield()的线程有可能在进入到可执行状态后马上又被执行。

2.sleep()可使优先级低的线程得到执行的机会,当然也可以让同优先级和高优先级的线程有执行的机会;而yield()方法只会给相同优先级或者更高优先级的线程一个运行的机会。

?

三.线程的同步和死锁

????????? 在多个线程操作中,多个线程可能要同时处理一个资源,此时就必须使用到同步。所谓的同步就是指在一个时间段内只能有一个线程执行指定代码,其他线程要等待此线程完成后才能执行。

??????

??????? 当多个线程同时读写同一份共享资源的时候,可能会引起冲突。这时候,我们需要引入线程“同步”机制,即各位线程之间要有个先来后到,不能一窝蜂挤上去抢作一团。
线程同步的真实意思和字面意思恰好相反。线程同步的真实意思,其实是“排队”:几个线程之间要排队,一个一个对共享资源进行操作,而不是同时进行操作。

?

线程实现同步有两种方法:

?

1.同步代码块

synchronized(同步标记){

???????要同步的代码

}

?

如:

public class Test {

	public static void main(String[] args) {

		myRunnable runnable = new myRunnable();

		//公用一份
		Thread thread1 = new Thread(runnable);		
		Thread thread2 = new Thread(runnable);

		// 不是马上执行线程,而是把线程置于就绪状态,等待CPU调用
		thread1.start();

		thread2.start();
	
	}
	
}

// 继承Thread类
class myRunnable implements Runnable {
	
	Object obj=new Object();//同步标记

	public void run() {
      synchronized(obj){
		int i = 0;
		try {
			while (true) {
                if(i==5)
                	break;
				System.out.println("子线程: " + i);
				i++;
				Thread.sleep(1000);// 休眠一秒
			}
		} catch (InterruptedException e) {
			e.printStackTrace();
		}

	}
	}
}

?

解释:若先thread1执行代码块,此时thread1会打上标记,可以理解为锁上门,当本次事件用完thread1还没执行完同步代码块;下一次thread2抢得cpu执行权,要执行此同步代码块,然而代码块被thread1上了锁,即打上了标记;此时thread2进不去,只能在门外干等把此次cpu事件消耗完。下一次若thread1抢得cpu执行权,本次thread1执行完代码块,即消除标记,打开门上的锁,下次若thread2抢得cpu执行权,则打上thread2的标记,执行同步代码块。

?

?

2.同步方法

public? synchronized void? method()

{
}

如:

// 继承Thread类
class myRunnable implements Runnable {
	
	Object obj=new Object();//同步标记

	public  synchronized void run() {
     
		this.myMethod();
	}
	
	public void myMethod()
	{
		int i = 0;
		try {
			while (true) {
                if(i==5)
                	break;
				System.out.println("子线程: " + i);
				i++;
				Thread.sleep(1000);// 休眠一秒
			}
		} catch (InterruptedException e) {
			e.printStackTrace();
		}

		
	}
}

?

此时标记的对象是当前对象this对象

?

两者的主要区别:代码块同步可以只同步方法里的部分代码,同步方法是同步整个方法

?

同步时可能会用线程干等浪费CPU处理时间,所以会导致性能下降。

?

2.线程的死锁

?

如:

线程1指向需要线程2的方法,而线程2执行需要线程1方法,此时双方都是同步的,都上了自己的标记,导致线程1不能执行线程2的方法,而线程2也不能执行线程1的方法.导致僵持。形成死锁。

?

过多的同步容易出现死锁,死锁一般是在程序运行过程中出现

?

?

?

?

?

发表评论
用户名: 匿名