Java多线程

Java进程与线程

进程是程序的一次动态执行过程,它经历了从代码加载、执行到执行完毕的一个完整过程,这个过程也是进程本身从产生、发展到最终消亡的过程。

多进程操作系统能同时运行多个进程(程序),由于CPU具备分时机制,所以每个进程都能循环获得自己的CPU时间片。

多线程是指一个进程在执行过程中可以产生多个线程,这些线程可以同时存在、同时运行,一个进程可能包含了多个同时执行的线程

比如JVM就是一个操作系统,每当使用java命令执行一个类时,实际上都会启动一个jvm,每一个JVM实际上就是在操作系统中启动一个进程,java本身具备了垃圾回收机制,所以每个java运行时至少会启动两个线程一个main线程另外一个是垃圾回收机制

Java中线程的实现

在Java中要想实现多线程代码有两种手段,一种是继承Thread类另一种就是实现Runnable接口

1.继承Thread类

class MyThread extends Thread{
	private String name;

	public MyThread(String name) {	//构造方法
		super();
		this.name = name;
	}
	
	public void run(){	//覆写Thread类中的run()方法
		for (int i=0;i<10;i++){
			System.out.println(name+"运行,i="+i);
		}
	}
	
}

public class Thread_demo {

	public static void main(String[] args) {
		// TODO 自动生成的方法存根
		MyThread mt1 = new MyThread("线程A ");
		MyThread mt2 = new MyThread("线程B ");
		mt1.start();
		mt2.start();
	}

}

输出的结果可能是A线程和B线程交替进行,哪一个线程对象抢到了CPU资源,哪个线程就可以运行,在线程启动时虽然调用的是start()方法,但是实际上调用的却是run()方法的主体

如果一个类通过Thread类来实现,那么只能调用一次start()方法,如果调用多次,则将会抛出"IllegalThreadStateException"异常。

 

2.实现Runnable接口

仍然要依靠Thread类完成启动,在Thread类中提供了public Thread(Runnable target)和public Thread(Runnable target,String name)两个构造方法。

这两个构造方法都可以接受Runnable的子类实例对象。

class MyThread_1 implements Runnable{
    private String name;
    
    public MyThread_1(String name) {    //构造方法
        super();
        this.name = name;
    }
    
    @Override
    public void run() {     //覆写Thread类中的run()方法
        // TODO 自动生成的方法存根
        for (int i=0;i<10;i++){
            System.out.println(name+"运行,i="+i);
        }
    }
    
}

public class Runnable_demo {

    public static void main(String[] args) {
        // TODO 自动生成的方法存根
        MyThread_1 mt1 = new MyThread_1("线程A ");    //实例化Runnable子类对象
        MyThread_1 mt2 = new MyThread_1("线程B ");    //实例化Runnable子类对象
        Thread t1 = new Thread(mt1);                            //实例化Thread类对象
        Thread t2 = new Thread(mt2);                            //实例化Thread类对象
        t1.start();                                                                    //启动线程
        t2.start();                                                                    //启动线程
    }

}

 

通过Thread和Runnable接口都可以实现多线程,其中Thread类也是Runnable接口的子类,但在Thread类中并没有完全地实现Runnable接口中的run()方法。

区别:如果一个类继承了Thread类,则不适合多个线程共享资源,而实现了Runnable接口,就可以方便地实现资源的共享。

如果在Thread子类覆盖的run方法中编写了代码,也为Thread子类对象传递了一个Runnable对象,线程运行的时候执行的是子类的run方法(匿名内部类对象的构造方法如何调用非默认构造方法)

 

class MyThread_2 implements Runnable{
	private int ticket = 5;	
	
	@Override
	public void run() {		//覆写Thread类中的run()方法
		// TODO 自动生成的方法存根
		for (int i=0;i<10;i++){
			if(ticket>0){
				System.out.println("卖票:ticket="+ticket--);
			}
		}
	}
	
}

public class Runnable_demo2 {

	public static void main(String[] args) {
		// TODO 自动生成的方法存根
		MyThread_2 mt = new MyThread_2();	//实例化Runnable子类对象
		Thread t1 = new Thread(mt);		//实例化Thread类对象
		Thread t2 = new Thread(mt);		//实例化Thread类对象
		Thread t3 = new Thread(mt);		//实例化Thread类对象
		t1.start();				//启动线程
		t2.start();				//启动线程
		t3.start();				//启动线程
	}

}

在没有同步之前会出现下面这种情况

 

实现Runnable接口相对于继承Thread类来说,有下列优势:

<1>适合多个相同程序代码的线程去处理同一资源的情况

<2>可以避免由于Java的单继承特性带来的局限

<3>增强了程序的健壮性,代码能够被多个线程共享,代码和数据是独立的

 

线程的生命周期

 

<1>设计4个线程对象,两个线程执行减操作,两个线程执行加操作

class Operator{
	
	private static int i;
	
	class Inc implements Runnable{
		
		@Override
		public void run() {
			// TODO 自动生成的方法存根
			for(int j=0;j<10;j++){
				this.inc();
				System.out.println(Thread.currentThread().getName()+",i="+i);
			}
		}
		
		public synchronized void inc(){
			i++;
		}
	}
	
	class Dec implements Runnable{
		
		@Override
		public void run() {
			// TODO 自动生成的方法存根
			for(int j=0;j<10;j++){
				this.dec();
				System.out.println(Thread.currentThread().getName()+",i="+i);
			}
		}
		
		public synchronized void dec(){
			i--;
		}
	}
}

public class Thread4_demo {
	
	public static void main(String[] args) {
		// TODO 自动生成的方法存根
		Operator.Inc inc1 = new Operator().new Inc();		//实例化内部类对象
		Operator.Inc inc2 = new Operator().new Inc();		//实例化内部类对象
		Operator.Dec dec1 = new Operator().new Dec();		//实例化内部类对象
		Operator.Dec dec2 = new Operator().new Dec();		//实例化内部类对象
		
		Thread t1 = new Thread(inc1);				//实例化Thread类对象
		Thread t2 = new Thread(inc2);				//实例化Thread类对象
		Thread t3 = new Thread(dec1);				//实例化Thread类对象
		Thread t4 = new Thread(dec2);				//实例化Thread类对象
		
		t1.start();
		t2.start();
		t3.start();
		t4.start();
	}

}

 

<2>设计一个生产电脑和搬运电脑类,要求生产出一台电脑就搬走一台电脑,如果没有新的电脑生产出来,则搬运工要等待新电脑产出;如果生产出的电脑没有搬走,则要等待电脑搬走之后再生产,并统计出生产的电脑数量。

class Computer {
	private String name = "未生产";
	private boolean flag = true;
	
	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}
	
	public synchronized void set(String name){	//设置信息名称及内容
		if(!flag){	//标志位为false,不可以生产,在这里等待取走
			try{
				super.wait();		//等待搬运者取走
			}catch(InterruptedException e){
				e.printStackTrace();
			}
		}	
		this.setName(name);			//设置信息名称	
		System.out.println(this.getName());	//输出信息
		try{
			Thread.sleep(300);		//加入延迟
		}catch(InterruptedException e){
			e.printStackTrace();
		}
		flag = false;				//标志位为true,表示可以取走
		super.notify();				//唤醒等待线程
	}
	
	public synchronized void get(){			//取得信息内容
		if(flag){				//标志位为true,不可以取走
			try{
				super.wait();		//等待生产者生产
			}catch(InterruptedException e){
				e.printStackTrace();
			}
		}		
		try {
			Thread.sleep(300);		//加入延迟
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
		this.setName("已经搬运完毕");
		System.out.println(this.getName());	//输出信息
		flag = true;				//修改标志位为true,表示可以生产
		super.notify();				//唤醒等待线程
	}
	
}

class producer implements Runnable{		//定义生产者线程

	private Computer com = null;		//保存Computer引用
	
	public producer(Computer com) {		//构造函数
		super();
		this.com = com;
	}

	@Override
	public void run() {
		int count = 0;
		// TODO 自动生成的方法存根
		for(int i=0;i<10;i++){
			this.com.set("已经生产完毕");
			count++;
		}
		System.out.println("生产的电脑数量:"+count);
	}
	
}

class transfer implements Runnable{		//定义生产者线程

	private Computer com = null;		//保存Computer引用
	
	public transfer(Computer com) {		//构造函数
		super();
		this.com = com;
	}

	@Override
	public void run() {
		// TODO 自动生成的方法存根
		for(int i=0;i<10;i++){
			this.com.get();
			
		}
	}
	
}

public class computer_transfer_demo {

	public static void main(String[] args) {
		// TODO 自动生成的方法存根
		Computer c = new Computer();
		producer pro = new producer(c);
		transfer tra = new transfer(c);
		new Thread(pro).start();
		new Thread(tra).start();
	}

}

java多线程操作方法

 

取得和设置线程名称

class MyThread_1 implements Runnable{	//实现Runnable接口
	private String name;
	
//	public MyThread_1(String name) {	//构造方法
//		super();
//		this.name = name;
//	}
	
	@Override
	public void run() {			//覆写Thread类中的run()方法
		// TODO 自动生成的方法存根
		for (int i=0;i<10;i++){
//			System.out.println(name+"运行,i="+i);
			System.out.println(Thread.currentThread().getName()+",i="+i);	//取出当前线程的名称
		}
	}
	
}

public class Runnable_demo {

	public static void main(String[] args) {
		
		MyThread_1 mt1 = new MyThread_1();	//实例化Runnable子类对象
		new Thread(mt1).start();		//系统自动设置线程名称
		new Thread(mt1,"线程A").start();		//手工自动设置线程名称
		new Thread(mt1,"线程B").start();		//手工自动设置线程名称
		new Thread(mt1).start();		//系统自动设置线程名称
		new Thread(mt1).start();		//系统自动设置线程名称
	}

}

手工设置线程名称    系统自动设置线程名称

        

判断线程是否启动

使用isAlive()方法来判断线程是否已经启动而且仍然在启动

class MyThread_1 implements Runnable{	//实现Runnable接口
	private String name;
	
	public MyThread_1(String name) {	//构造方法
		super();
		this.name = name;
	}
	
	@Override
	public void run() {			//覆写Thread类中的run()方法
		// TODO 自动生成的方法存根
		for (int i=0;i<10;i++){
//			System.out.println(name+"运行,i="+i);
			System.out.println(Thread.currentThread().getName()+",i="+i);	//取出当前线程的名称
		}
	}
	
}

public class Runnable_demo {

	public static void main(String[] args) {
		// TODO 自动生成的方法存根
		MyThread_1 mt1 = new MyThread_1("线程A ");	//实例化Runnable子类对象
		MyThread_1 mt2 = new MyThread_1("线程B ");	//实例化Runnable子类对象
		Thread t1 = new Thread(mt1);			//实例化Thread类对象
		Thread t2 = new Thread(mt2);			//实例化Thread类对象
		System.out.println("线程开始执行之前-->"+t1.isAlive());
		t1.start();						//启动线程
		System.out.println("线程开始执行之后-->"+t1.isAlive());
		t2.start();						//启动线程

	}

}

 主线程有可能比其他线程先执行完

 

线程的强制运行

在线程操作中,可以使用join()方法让一个线程强制运行,线程强制运行期间,期间线程无法运行,必须等待此线程完成之后才可以继续执行。

线程的休眠

在程序中允许一个线程进行暂时的休眠,直接使用Thread.sleep()方法即可实现休眠

程序在执行的时候,每次的输出都会间隔500ms,达到了延时操作的效果。

Thread.sleep()方法要用try和catch语句包围

class Mythread implements Runnable{	//实现Runnable接口
	
	@Override
	public void run() {		//覆写Thread类中的run()方法
		// TODO 自动生成的方法存根
		for (int i=0;i<5;i++){
			try{
				Thread.sleep(500);			//线程休眠
			}catch (Exception e){}				//需要异常处理
				System.out.println(Thread.currentThread().getName()+",i="+i);	//取出当前线程的名称
		}
	}
	
}

public class ThreadSleep_demo {

	public static void main(String[] args) {
		// TODO 自动生成的方法存根
		Mythread m = new Mythread();
		new Thread(m,"线程").start();
	}

}

 

中断线程

当一个线程运行时,另外一个线程可以直接通过interrupt()方法中断其运行状态。

一个线程启动之后进入了休眠状态,原来是要休眠10s之后再继续执行,但是主方法在线程启动之后的2s之后就将其中断,休眠一旦中断之后将执行catch中的代码。

class Mythread_1 implements Runnable{	//实现Runnable接口
	
	@Override
	public void run() {		//覆写Thread类中的run()方法
		// TODO 自动生成的方法存根
		System.out.println("进入run方法");
		try{
			Thread.sleep(10000);		//线程休眠
			System.out.println("休眠完成");
				}catch (Exception e){	//需要异常处理
			System.out.println("休眠被终止");
			return;				//让程序返回被调用处
		}
		System.out.println("run方法结束");
	}
	
}

public class ThreadInterrupt_demo {

	public static void main(String[] args) {
		// TODO 自动生成的方法存根
		Mythread_1 m = new Mythread_1();
		Thread t = new Thread(m,"线程");
		t.start();
		try{
			Thread.sleep(2000);		//主线程2s之后再执行中断
		}catch(Exception e){}
		t.interrupt();
	}

}

 

后台线程

在Java程序中,只要前台有一个线程在运行,则整个Java进程都不会消失,所以此时可以设置一个后台线程,这样即使Java进程结束了,此后台线程依然会继续执行。要想实现这样的操作,直接使用setDaemon()方法即可。

 

线程的优先级

在Java的线程中使用setPriority()方法可以设置一个线程的优先级,在Java的线程中一共有3种优先级。

class MyThread_1 implements Runnable{	//实现Runnable接口
	private String name;
	
//	public MyThread_1(String name) {	//构造方法
//		super();
//		this.name = name;
//	}
	
	@Override
	public void run() {			//覆写Thread类中的run()方法
		// TODO 自动生成的方法存根
		for (int i=0;i<10;i++){
			//System.out.println(name+"运行,i="+i);
			System.out.println(Thread.currentThread().getName()+",i="+i);	//取出当前线程的名称
		}
	}
	
}

public class Runnable_demo {

	public static void main(String[] args) {
		// TODO 自动生成的方法存根
		MyThread_1 mt1 = new MyThread_1();	//实例化Runnable子类对象
		MyThread_1 mt2 = new MyThread_1();	//实例化Runnable子类对象
		MyThread_1 mt3 = new MyThread_1();	//实例化Runnable子类对象
		Thread t1 = new Thread(mt1,"线程A");	/实例化Thread类对象
		Thread t2 = new Thread(mt2,"线程B");	//实例化Thread类对象
		Thread t3 = new Thread(mt3,"线程C");	//实例化Thread类对象
//		System.out.println("线程开始执行之前-->"+t1.isAlive());
		t1.setPriority(Thread.MIN_PRIORITY);
		t2.setPriority(Thread.NORM_PRIORITY);
		t3.setPriority(Thread.MAX_PRIORITY);
		t1.start();						//启动线程
//		System.out.println("线程开始执行之前-->"+t1.isAlive());
		t2.start();						//启动线程
		t3.start();						//启动线程
		
//		MyThread_1 mt1 = new MyThread_1();	//实例化Runnable子类对象
//		new Thread(mt1).start();				//系统自动设置线程名称
//		new Thread(mt1,"线程A").start();				//手工自动设置线程名称
//		new Thread(mt1,"线程B").start();				//手工自动设置线程名称
//		new Thread(mt1).start();				//系统自动设置线程名称
//		new Thread(mt1).start();				//系统自动设置线程名称
	}

}

 线程将根据优先级的大小来决定哪个线程会先运行,但是并非线程的优先级越高就一定会先执行,哪个线程先执行将由CPU的调度决定。

主方法的优先级是NORM,通过Thread.currentThread().getPriority()来取得主方法的优先级,结果是5

 

线程的礼让

在线程的操作中,可以使用yield()方法将一个线程的操作暂时让给其他线程执行。本线程暂停,让其他进程先执行。

class MyThread_1 implements Runnable{	//实现Runnable接口
	private String name;
	
//	public MyThread_1(String name) {	//构造方法
//		super();
//		this.name = name;
//	}
	
	@Override
	public void run() {								//覆写Thread类中的run()方法
		// TODO 自动生成的方法存根
		for (int i=0;i<10;i++){
			//System.out.println(name+"运行,i="+i);
			System.out.println(Thread.currentThread().getName()+",i="+i);	//取出当前线程的名称
			if(i==3){
				System.out.println("线程礼让:");
				Thread.currentThread().yield();	//线程礼让
			}
		}
	}
	
}

public class Runnable_demo {

	public static void main(String[] args) {
		// TODO 自动生成的方法存根
		MyThread_1 mt1 = new MyThread_1();	//实例化Runnable子类对象
		MyThread_1 mt2 = new MyThread_1();	//实例化Runnable子类对象
		MyThread_1 mt3 = new MyThread_1();	//实例化Runnable子类对象
		Thread t1 = new Thread(mt1,"线程A");	//实例化Thread类对象
		Thread t2 = new Thread(mt2,"线程B");	//实例化Thread类对象
		Thread t3 = new Thread(mt3,"线程C");	//实例化Thread类对象
//		System.out.println("线程开始执行之前-->"+t1.isAlive());
		t1.setPriority(Thread.MIN_PRIORITY);
		t2.setPriority(Thread.NORM_PRIORITY);
		t3.setPriority(Thread.MAX_PRIORITY);
		t1.start();				//启动线程
//		System.out.println("线程开始执行之前-->"+t1.isAlive());
		t2.start();				//启动线程
		t3.start();				//启动线程
		
//		MyThread_1 mt1 = new MyThread_1();	//实例化Runnable子类对象
//		new Thread(mt1).start();				//系统自动设置线程名称
//		new Thread(mt1,"线程A").start();				//手工自动设置线程名称
//		new Thread(mt1,"线程B").start();				//手工自动设置线程名称
//		new Thread(mt1).start();				//系统自动设置线程名称
//		new Thread(mt1).start();				//系统自动设置线程名称
	}

}

     

线程礼让也是不一定的

posted @ 2016-03-07 21:43  tonglin0325  阅读(433)  评论(0编辑  收藏  举报