现在的位置: 首页 > 综合 > 正文

java 多线程

2017年08月15日 ⁄ 综合 ⁄ 共 3033字 ⁄ 字号 评论关闭

线程的概念:

程序 进程与线程的区别:

  程序是一个静态的代码或者说静态的存在.而进程是程序的一次运行过程. 

  多个进程的内部数据和状态都是完全独立的,而多线程是共享一块内存空间和一组系统资源,有可能互相影响.

  线程本身的数据通常只有寄存器数据,以及一个程序执行时使用的堆栈,所以线程的切换比进程切换的负担要小。



线程的实现方法:

继承Thread类

      Thread 类是一个具体的类,即不是抽象类,该类封装了线程的行为。要创建一个线程,程序员必须创建一个

 Thread 类导出的新类。程序员必须覆盖 Thread 的 run() 函数来完成有用的工作。用户并不直接调用此函数;而是必

须调用 Thread 的 start() 函数,该函数再调用 run()。

实现Runnable接口

     有时要作为线程运行的类可能已经是某个类层次的一部分,所以就不能再按这种机制创建线程。对于这种情况,就

要 runnable 接口.实现Runnable接口, 提供run()方法的具体实现, 最后生成该类的实例, 并作为参数传入Thread类的构造

方法来创建线程。可以从其他类继承,简化类层次,并将Thread类与任务处理类分开。

实例代码分别如下:

public class myThread01 extends Thread {
	private int i = 0;

	public myThread02(String str) {
		super(str);
	}

	public void run() {

		while (i < 100) {
			System.out.println(getName() + " 完成了" + i + "% 的工作");
			i++;
			try {
				Thread.sleep(1000);
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		}
	}

	public static void main(String[] args) {
		new myThread01("worker01").start();
		new myThread01("worker02").start();
		new myThread01("worker03").start();
		new myThread01("worker04").start();
	}

}

public class myThread02 implements Runnable {
	private int i = 0;

	public void run() {

		while (i < 100) {
			System.out.println(Thread.currentThread().getName() + " 完成了" + i
					+ "% 的工作");
			i++;
			try {
				Thread.sleep(1000);
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		}
	}

	public static void main(String[] args) {
		myThread02 mt = new myThread02();
		for (int i = 0; i < 4; i++) {
			new Thread(mt).start();
		}
	}

}

线程的生命周期:

新状态:线程已被创建但尚未执行(start() 尚未被调用)。

可执行状态:线程可以执行,虽然不一定正在执行。CPU 时间随时可能被分配给该线程,从而使得它执行。

死亡状态:正常情况下 run() 返回使得线程死亡。调用 stop()或 destroy() 亦有同样效果,但是不被推荐,前者会产生异

常,后者是强制终止,不会释放锁。

阻塞状态:线程没有被分配 CPU 时间,无法执行。



线程退出最好自己实现,在运行状态中一直检验一个状态,如果这个状态为真,就一直运行,如果外界更改了这个状态变量,那么线程就停止运行。 

1.sleep()方法

在指定时间内让当前正在执行的线程暂停执行,但不会释放“锁标志”。不推荐使用。sleep()使当前线程进入阻塞状态,

在指定时间内不会执行。

2.wait()方法

在其他线程调用对象的notify或notifyAll方法前,导致当前线程等待。线程会释放掉它所占有的“锁标志”,从而使别的线

程有机会抢占该锁。一直等到有人通知我,我才会运行后面的代码。 

当前线程必须拥有当前对象锁。如果当前线程不是此锁的拥有者,会抛出IllegalMonitorStateException异常。

唤醒当前对象锁的等待线程使用notify或notifyAll方法,也必须拥有相同的对象锁,否则也会抛出

IllegalMonitorStateException异常。(notify()方法表示,当前的线程已经放弃对资源的占有, 通知等待的线程来获得对资源的占有权,但是只有一个线程能够从wait状态中恢复, 然后继续运行wait()后面的语句; notifyAll()方法表示,当前的线程已经放弃对资源的占有, 通知所有的等待线程从wait()方法后的语句开始运行。

wait() 和notify()必须在synchronized函数或synchronized block中进行调用。如果在non-synchronized函数或non-

synchronized block中进行调用,虽然能编译通过,但在运行时会发生 IllegalMonitorStateException的异常。

3.yield方法

暂停当前正在执行的线程对象。yield()只是使当前线程重新回到可执行状态,所以执行yield()的线程有可能

在进入到可执行状态后马上又被执行。yield()只能使同优先级或更高优先级的线程有执行的机会。

4.join方法

等待该线程终止。等待调用join方法的线程结束,再继续执行。如:t.join();//主要用于等待t线程运行结束,若无此句,

main则会执行完毕,导致结果不可预测。


线程的同步:

一个Java程序的多线程之间可以共享数据。当线程以异步方式访问共享数据时,有时候是不安全的或者不和逻辑的。

比如,同一时刻一个线程在读取数据,另外一个线程在处理数据,当处理数据的线程没有等到读取数据的线程读取完毕

就去处理数据,必然得到错误的处理结果。 

Java 编程语言提供了一种简单的机制来防止发生这种覆盖。每个对象在运行时都有一个关联的锁。这个锁可通过为方

法添加关键字 synchronized 来获得。


同步有两种方式:

同步块:对易发生冲突的语句块加锁 

同步方法:对易发生冲突的方法块加锁

分别实例如下:

class SellThread implements Runnable {
		int tickets = 100;
		Object obj = new Object();

		public void run() {
			while (true) {
				synchronized (obj) {
					if (tickets > 0) {
						System.out.println(Thread.currentThread().getName()
								+ " sell tickets:" + tickets);
						tickets--;
					}
				}
			}
		}
	}

class SellThread implements Runnable{
     int tickets=100;
     public void run(){  
         sell(); 
     }
     public synchronized void sell(){
         while(true){  
	 if(tickets>0){	
    	      System.out.println(Thread.currentThread().getName()+
						" sell tickets:"+tickets  
                  tickets--;
             }
         }		
     }	
}

【上篇】
【下篇】

抱歉!评论已关闭.