java 多线程基本操作总结

java能够支持多线程,多线程是实现并发机制的一种有效手段,和进程一样,线程也是实现并发的一个基本单位,但是线程是比进程更小的单位,线程是在进程的基础上的进一步划分。所谓所线程就是说一个进程在运行的过程中可以产生多个线程,这些线程可以同时存在,同时运行,一个进程可能包含有多个同时执行的线程。

首先,线程的实现:直接继承Thread类和实现Runnable接口。这两种方式都能够实现多线程先给出例子:

继承Thread类:

class ThreadT extends Thread{
	
	public ThreadT(String name) {
		super(name);
	}

	@Override
	public void run() {
		for(int i=0;i<20;i++)
			System.out.println(this.getName()+"running"+i);
	}
}
public class ThreadTest {
	public static void main(String[] args) {
		new ThreadT("Thread线程一").start();
		new ThreadT("Thread线程二").start();
	}
}
/**
 * 结果:
 * 
 * Thread线程一running0
Thread线程一running1
Thread线程一running2
Thread线程二running0
Thread线程一running3
Thread线程二running1
Thread线程一running4
Thread线程二running2
Thread线程一running5
Thread线程二running3
Thread线程二running4
Thread线程二running5
Thread线程二running6
Thread线程二running7
 */

启动线程不能直接调用run()方法,必须调用start()方法,因为线程的执行需要cpu的调度,同时每个线程都只能调用一次start()方法

实现Runnable接口的多线程:两个线程一个打印“-”一个打印“|”同时打印:

public class ThreadTest01 {
	public static void main(String[] args) {
//		new Thread(new PrintHeng()).start();
//		new Thread(new PrintShu()).start();
		RunnableTest runnable1=new RunnableTest();
		new Thread(runnable1,"thread1").start();
		new Thread(runnable1,"thread2").start();
		new Thread(runnable1,"thread3").start();
		new Thread(runnable1,"thread4").start();
	}
}

class PrintHeng implements Runnable{  // 打印横线的线程
	public void run() {
		for(int i=0;i<20;i++)
		{
			System.out.print("-");
			try {
				Thread.sleep(200);
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		}
	}
	
}

class PrintShu implements Runnable{  // 打印竖线的线程
	public void run() {
		for(int i=0;i<20;i++)
		{
			System.out.println("|");
			try {
				Thread.sleep(300);
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		}
	}
}
运行能同时打印横线和竖线,但是注意到 线程的start方法调用还是通过Thread类来实现的,这一点下面会给出解释

既然通过Thread类和Runnable接口都可以实现多线程,那么这两种方法有什么区别呢,首先给出Thread类的定义:

public class Thread implements Runnable {
	//...     中间很多变量省略
	           
	
	//...
	/* What will be run. */
    private Runnable target;         // 将目标线程作为自己的参数
    
  //...     中间部分省略
    
	
  	//...
    
    public void run() {
    	if (target != null) {      // 实际上就是调用了目标线程的run方法
    	    target.run();
    	}
        }


}
从定义中可以看出,Thread类也实现了Runnable 的接口,如果我们自己实现的线程也是实现Runnable接口方式的话就有了下面的关系:

可见当我们Thread类就相当于是我们目标线程(MyThread)的一个代理,通过target的start()方法来调用MyThread中的run方法,而不是直接运行我们Mythread中的run(),因为直接调用run()的话并不需要cpu的调度相当于执行了一个普通方法。

除此之外两种方式在共享变量时也是有所区别的,使用一个简单的例子:

package edu.hue.jk.thread;

class MyThread extends Thread{
	private int i=0;
	public void run(){
		System.out.println("Thread继承方式:"+"----"+i++);
	}
	public MyThread() {
		super();
	}
}

public class ThreadTest02 {
	public static void main(String[] args) {
		for(int i=0;i<10;i++)
			new Thread(new MyThread()).start();
		try {
			Thread.sleep(1000);
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
		MyRunnable runnable=new MyRunnable();
		for(int i=0;i<10;i++)
			new Thread(runnable).start();  // 构造同一实例的多个线程
	}
}
class MyRunnable implements Runnable{
	private int i=0;
	public void run() {
		System.out.println("Runnable实现方式:"+"----"+i++);
	}
	public MyRunnable() {
		super();
	}
}

实验结果:

Thread继承方式:----0
Thread继承方式:----0
Thread继承方式:----0
Thread继承方式:----0
Thread继承方式:----0
Thread继承方式:----0
Thread继承方式:----0
Thread继承方式:----0
Thread继承方式:----0
Thread继承方式:----0
Runnable实现方式:----0
Runnable实现方式:----1
Runnable实现方式:----2
Runnable实现方式:----3
Runnable实现方式:----4
Runnable实现方式:----5
Runnable实现方式:----6
Runnable实现方式:----7
Runnable实现方式:----8
Runnable实现方式:----9

说明使用Runnable方式实现多线程时候,可以实现多个线程共享同一个实例(资源共享的效果)。



三个静态方法用来控制进程的优先级:

static int MAX_PRIORITY
          线程可以具有的最高优先级。
static int MIN_PRIORITY
          线程可以具有的最低优先级。
static int NORM_PRIORITY
          分配给线程的默认优先级。
 
构造方法摘要
Thread(Runnable target)
          分配新的 Thread 对象。
Thread(String name)
          分配新的 Thread 对象。
 
 
其它方法
static Thread currentThread()
          返回对当前正在执行的线程对象的引用。
 ClassLoader getContextClassLoader()
          返回该线程的上下文 ClassLoader。
 long getId()
          返回该线程的标识符。
 String getName()
          返回该线程的名称。
 int getPriority()
          返回线程的优先级。
 Thread.State getState()
          返回该线程的状态。
 ThreadGroup getThreadGroup()
          返回该线程所属的线程组。
static boolean holdsLock(Object obj)
          当且仅当当前线程在指定的对象上保持监视器锁时,才返回 true。
 void interrupt()
          中断线程。
static boolean interrupted()
          测试当前线程是否已经中断。
 boolean isAlive()
          测试线程是否处于活动状态。
 boolean isDaemon()
          测试该线程是否为守护线程。
 boolean isInterrupted()
          测试线程是否已经中断。
 void join()
          等待该线程终止。
 void join(long millis)
          等待该线程终止的时间最长为 millis 毫秒。
 void join(long millis, int nanos)
          等待该线程终止的时间最长为 millis 毫秒 + nanos 纳秒。
 void resume()
          已过时。 该方法只与 suspend() 一起使用,但 suspend() 已经遭到反对,因为它具有死锁倾向。有关更多信息,请参阅为何 Thread.stop、Thread.suspend 和 Thread.resume 遭到反对?。
 void run()
          如果该线程是使用独立的 Runnable 运行对象构造的,则调用该 Runnable 对象的 run 方法;否则,该方法不执行任何操作并返回。
 void setContextClassLoader(ClassLoader cl)
          设置该线程的上下文 ClassLoader。
 void setDaemon(boolean on)
          将该线程标记为守护线程或用户线程。
static void setDefaultUncaughtExceptionHandler(Thread.UncaughtExceptionHandler eh)
          设置当线程由于未捕获到异常而突然终止,并且没有为该线程定义其他处理程序时所调用的默认处理程序。
 void setName(String name)
          改变线程名称,使之与参数 name 相同。
 void setPriority(int newPriority)
          更改线程的优先级。
 void setUncaughtExceptionHandler(Thread.UncaughtExceptionHandler eh)
          设置该线程由于未捕获到异常而突然终止时调用的处理程序。
static void sleep(long millis)
          在指定的毫秒数内让当前正在执行的线程休眠(暂停执行)。
static void sleep(long millis, int nanos)
          在指定的毫秒数加指定的纳秒数内让当前正在执行的线程休眠(暂停执行)。
 void start()
          使该线程开始执行;Java 虚拟机调用该线程的 run 方法。
 void stop()  停止线程
 void stop(Throwable object)
 void suspend()  线程挂起
 String toString()
          返回该线程的字符串表示形式,包括线程名称、优先级和线程组。
static void yield()
         线程让步, 暂停当前正在执行的线程对象,并执行其他线程。

除此之外还可以使用object中的三个方法来对进程进行调度:

  this.notify();    // 唤醒另外一个进程
  this.notifyAll(); // 唤醒所有进程
  this.wait();      // 等待
  this.wait(timeout);  // 等待多长时间

使用进程同步:用一个例子来说明同步的重要性

package edu.hue.jk.thread;


//要理解进程同步首先要搞清楚进程同步的定义:
/**
 * 在操作系统中进程同步是指,系统中多个进程中发生的事件存在某种时序关系,需要相互协作,共同完成任务。具体的说一个线程运行在某一点时
 * 需要另外一个线程为它提供消息,在未获得消息之前一直处在等待状态,获得消息之后该进程被唤醒处于就绪状态。而且当多个线程访问同一份资源(贡献资源)
 * 的时候,可能会引起冲突,所以要加入同步机制来控制多个线程之间的访问顺序,一遍造成读写不一致的情况。
 * 现在假设一个网上售票系统,有三个点可以售票,假设总共有五张票,程序如下:
 * @author dell
 *
 */
public class WhySynchronized {

	/**
	 * @param args
	 */
	public static void main(String[] args) {
		TiketThread tiket=new TiketThread();
		new Thread(tiket,"tiket1").start();
		new Thread(tiket,"tiket2").start();
		new Thread(tiket,"tiket3").start();
	}

}
class TiketThread implements Runnable{  //  充分说明了进程同步的重要性
	static int tiket=5;
	public void run() {
		//synchronized(this){    // 不使用同步
		while(true){
			if(tiket>0)
			{
				try {
					Thread.sleep(200);   //  加入延时方便查看期待的结果
				} catch (InterruptedException e) {
					e.printStackTrace();
				}
				System.out.println(Thread.currentThread().getName()+"selling tikets"+tiket);
				tiket--;
			}
			else
				break;
		}
		//}
	}
	
}

可见没有使用同步,使得多线程的使用得不到我们需要的效果,将使用同步的注释去掉就可以得到正确的结果。

为了跟进一步的理解进程的同步使用方法,以及如何去操作进程,引入生产者和消费者的两个例子:

<span style="color:#000000;">package edu.hue.jk.thread;

/**
 * 用来描述生产者消费者问题          生产者不断的生产产品,消费者不断的取出产品;生产者生产一个产品,消费者就要取出一个产品,生产者不能连续生产,消费者也不能连续取产品
 * 对于生产者和消费者来说,产品就是共享资源,而且不能同时去控制产品,所以使用同步操作
 * 使用信号量来控制生产者和消费者的协调工作:
 * s1=1 表示生产者可以生产,s1=0表示不能生产  初始值为1
 * s1=0表示消费者可以取产品  s1=1 表示不能取  
**/
public class ProduceAndConsumer {
	public static void main(String[] args) {
		Product pro=new Product();
		pro.setS1(1);
		new Thread(new Produce(pro)).start();
		new Thread(new Consumer(pro)).start();  // 这里要怎样修改
	}  
}
class Product{
	private String productName;
	int s1=1;  // 用来协调生产者和消费者的信号量
	
	public int getS1() {
		return s1;
	}
	public void setS1(int s1) {
		this.s1 = s1;
	}
	public String getProductName() {
		return productName;
	}
	public void setProductName(String productName) {
		this.productName = productName;
	}
}

class Produce implements Runnable{
	Product product;
	
	public Produce(Product product) {
		super();
		this.product = product;
		
	}
	public void run() {
		while(true){  // 生产者不断的生产产品
			synchronized(product){    //使用同步块
				if(product.getS1()==1)      // 能够生产
				{
					product.setProductName("productName");
					System.out.println("生产产品:"+product.getProductName());
					try {
						Thread.sleep(300);
					} catch (InterruptedException e) {
						e.printStackTrace();
					}
					product.setS1(0);   // 生产者生产之后消费者能够取出产品
					product.notify();  // 唤醒消费者
				}
				else  // 不能够生产
				{
					
					System.out.println("不能生产产品:");
					try {
						Thread.sleep(300);
					} catch (InterruptedException e) {
						e.printStackTrace();
					}
					
					try {
						product.wait();  // 等待
					} catch (InterruptedException e) {
						e.printStackTrace();
					}
				}
		}
	}
	
	}
}
class Consumer implements Runnable{
	Product product;
	public Consumer(Product product) {
		super();
		this.product = product;
	}
	public void run() {
		while(true){
			synchronized(product){
				if(product.getS1()==0)
				{
					System.out.println("消费者取出产品:"+product.getProductName());
					try {
						Thread.sleep(300);
					} catch (InterruptedException e) {
						e.printStackTrace();
					}
					product.setS1(1);
					product.notify();  // 唤醒生产者
				}
				else
				{
					
					System.out.println("不能取出产品:");
					try {
						Thread.sleep(300);
					} catch (InterruptedException e) {
						e.printStackTrace();
					}
					
					try {
						product.wait();
					} catch (InterruptedException e) {
						e.printStackTrace();
					}
				}
		
			}
		}
	}
	
}</span>

得到的结果

生产产品:productName
不能生产产品:
消费者取出产品:productName
不能取出产品:
生产产品:productName
不能生产产品:
消费者取出产品:productName
不能取出产品:
生产产品:productName
不能生产产品:
消费者取出产品:productName
不能取出产品:
生产产品:productName

生产者消费者问题变形:

<span style="color:#000000;">package edu.hue.jk.thread;
import java.util.LinkedList;
import java.util.List;

/**
 *<span style="color:#cc0000;"> 生产者和消费者问题变形: 现在有一个容量固定的缓冲区,缓冲区满时生产者停止生产,缓冲区空时消费者停止消费
 * 前边使用的是同步块,下面使用同步方法来实现
 * @author dell
</span> *
 */
public class ProduceAndConsumer02 {
	public static void main(String[] args) {
		ProductList list=new ProductList(5);
		new Thread(new Produce02(list)).start();
		new Thread(new Consumer02(list)).start();
	}

}
class Product02 {
	String productName;
	public String getProductName() {
		return productName;
	}
	public void setProductName(String productName) {
		this.productName = productName;
	}
	public Product02(String productName) {
		super();
		this.productName = productName;
	}
	
}
// 表示缓冲区
class ProductList{
	int length ;// 表示缓冲区的容量
	int i=1;  // 表示铲平的序号
	List<Product02> productList;
	public ProductList(int length) {
		super();
		this.length = length;
		productList=new LinkedList<Product02>();
	}
	public ProductList() {
		super();
		productList=new LinkedList<Product02>();
	}
	// 使用同步方法生产产品
	public synchronized  void ProduceAProduct(){
		while(true){
			try {
				Thread.sleep(300);
			} catch (InterruptedException e1) {   //为了观察效果而设置的延迟操作
				e1.printStackTrace();
			}  //  
			if(length>productList.size()){   // 可以继续生产产品
				Product02 pro=new Product02("product"+i);
				productList.add(pro);  // 加入缓冲区
				System.out.println("生产产品:"+pro.getProductName());
				i++;
				notify();
			}
			else{
				try {
					System.out.println("生产者等待。。。。。。");
					wait();
				} catch (InterruptedException e) {
					
					e.printStackTrace();
				}
			}
		}
		
	}
	public synchronized  void getAProduct(){
		while(true){
			try {
				Thread.sleep(300);
			} catch (InterruptedException e1) {
				e1.printStackTrace();
			}  //  
			if(productList.size()>0){   // 可以继续生产产品
				Product02 pro=productList.get(0); // 始终取第一个产品
				productList.remove(0);   // 从缓冲区取出
				System.out.println("消费者取出:"+pro.getProductName());
				notify();
			}
			else{
				try {
					System.out.println("消费者等待。。。。。。");
					wait();
				} catch (InterruptedException e) {
					
					
					e.printStackTrace();
				}
			}
		}
		
	}
}
class Produce02 implements Runnable{
	ProductList list;
	public void run() {
		list.ProduceAProduct();
	}
	public Produce02(ProductList list) {
		super();
		this.list = list;
	}
}
class Consumer02 implements Runnable{
	ProductList list;
	public void run() {
		list.getAProduct();
	}
	public Consumer02(ProductList list) {
		super();
		this.list = list;
	}
}</span>


运行结果:

生产产品:product1
生产产品:product2
生产产品:product3
生产产品:product4
生产产品:product5
生产者等待。。。。。。
消费者取出:product1
消费者取出:product2
消费者取出:product3
消费者取出:product4
消费者取出:product5
消费者等待。。。。。。
生产产品:product6
生产产品:product7
生产产品:product8
生产产品:product9
生产产品:product10
生产者等待。。。。。。
消费者取出:product6


 


 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值