线程的实例讲解

上一节我们讲解了进程和线程的区别,概念比较繁重,可能读者会出现大脑昏晕的状态,接下来我就实例讲解一下具体的使用,供大家更加深入的理解概念:

(一)操作进程:在Java代码中如何运行一个进程,主要有两种方式:

实现功能:在Java程序中如何开启一个进程:运行记事本程序!

方式一:Runtime类的exec()方法即可开启一个进程(每一个应用程序中都会有一个Runtime类的实例对象,这个类构造函数私有,对象单例

//方式一:使用Runtime类的exec()方法
		Runtime runtime = Runtime.getRuntime();
		try {
			runtime.exec("notepad");
		} catch (IOException e) {
			e.printStackTrace();http://blog.csdn.net/super_yc/article/details/73294203
		}


方式二ProcessBuilder 类中的start()方法就可以开启一个进程:

//方式二:ProcessBuilder的start()方法
		ProcessBuilder pb = new ProcessBuilder("notepad");
		try {
			pb.start();
		} catch (IOException e) {
			e.printStackTrace();
		}


(二)操作线程,创建和启动线程在传统上有两种方式:

方式一:继承Thread(本质上Thread 类也实现了Runnable 接口)

步骤

1)定义一个类继承于java.lang.Thread类;

2)SubThread类中覆盖Thread类中的run()方法;

3)run()方法中编写需要执行的操作------->run()方法里即为线程执行体;

4)main()方法(线程)中,创建线程对象,并启动线程!

创建线程类对象 SubThread st = new SubThread();

调用线程对象中的start()方法st.start()//启动一个线程

注意:在创建线程对象后,直接调用run()方法,依然只有一个线程,就是主线程,并没有开启一个新线程;和普通方法调用等同,依然串行执行!

 

方式二实现Runnable接口;

步骤:

1)定义一个类实现接口java.lang.Runnable接口;

2)Sub类中覆盖Runnable接口中的run()方法;

3)run()方法中编写需要执行的操作------->run()方法里,线程执行体;

4)main()方法中创建线程对象,并且启动线程!

创建线程类对象:    Thread t = new Thread( new Sub() );

调用线程对象的start()方法:t.start();

使用实现Runnable接口创建线程,先判断target不为空,直接调用实现类中的run()方法!(运行时,动态绑定,多态实现!)

  @Override
    public void run() {
        if (target != null) {
            target.run();
        }
    }



注意:默认的Thread.run()就是直接调用内部的Runabble接口,因此使用Runnable接口告诉线程该做什么,比较合理。要使用Thread(Runnable target)的构造函数,实现Runnable接口的类,想要开启一个线程,必然要调用start()方法,但Runnable接口中没有此方法,所以必须要借助Thread类的API来启动线程!(Thread本质上也是Runabble接口的实现类)

【示例】

 /*
 * 案例:存在50个苹果,现在有请三个童鞋(小A,小B,小C)上台表演吃苹果,因为A,B,C三个人可以同  * 时吃苹果,此时得使用多线程技术来实现这个案例,
 * 分析:可以定义三个线程对象,并启动线程,每个同学吃苹果的时候:先展示自己拿到手上苹果的编  * 号,如1,2,3,4.....50,再吃掉苹果 (意味着苹果总数减少一个)
 */

方式一可以使用继承Thread类的方式来实现(继承执行失败,不能实现其功能!)

//方式一:可以使用继承Thread类的方式来实现;
public class EatAppleGame {
	public static void main(String[] args) {
		//创建申请那个线程(同学),吃苹果
		Person p1 = new Person("小A");
		Person p2 = new Person("小B");
		Person p3 = new Person("小C");
		p1.start();
		p2.start();
		p3.start();
	}
}

class Person extends Thread{
	//表示苹果总数
	private int num = 50;
	public Person(String name) {
		super(name);
	}
	public void run(){
		for (int i = 0; i < 50; i++) {
			if(num > 0){
				System.out.println(super.getName() + "吃了编号为:" + num-- + "的苹果!");
			}
		}
	}
}


方式二:通过继承Thread类来实现临界资源的共享:(可以实现资源共享,Thread类本质上也实现了Runnable接口)

//方式二:可以使用继承Thread类的方式来实现;
public class EatAppleGame {
	public static void main(String[] args) {
		//创建申请那个线程(同学),吃苹果,创建三个对象,资源不能共享
		Person p = new Person();
		new Thread(p,"小A").start();
		new Thread(p,"小B").start();
		new Thread(p,"小C").start();
	}
}

class Person extends Thread{
	//表示苹果总数
	private int num = 50;
	
	public void run(){
		for (int i = 0; i < 50; i++) {
			if(num > 0){
				System.out.println(Thread.currentThread().getName() + "吃了编号为:" + num-- + "的苹果!");
			}
		}
	}
}



方式三:可以使用实现Runnable接口的方式来实现(实现接口成功,可实现其功能!)


//方式三:可以使用实现Runnable接口的的方式来实现;
public class EatAppleImpl {
	public static void main(String[] args) {
		//创建申请那个线程(同学),吃苹果
		Apple a = new Apple();
		//三个线程共享Apple中的成员变量资源(num资源)
		new Thread(a,"小A").start();
		new Thread(a,"小B").start();
		new Thread(a,"小C").start();
	}
}

class Apple implements Runnable{
	private int num = 50;
	public void run(){
		for (int i = 0; i < 50; i++) {
			if(num > 0){
				String threadName = Thread.currentThread().getName();//获取当前的线程,进而获取线程名称
				System.out.println(threadName + "吃了编号为:" + num-- + "的苹果!");
			}
		}
	}
}



对应上述代码,出现这种结果情况:

小B吃了编号为:50的苹果!
小A吃了编号为:49的苹果!
小C吃了编号为:49的苹果!
小A吃了编号为:48的苹果!
小B吃了编号为:46的苹果!
小C吃了编号为:47的苹果!

以及这种情况:

小A吃了编号为:3的苹果!
小C吃了编号为:2的苹果!
小C吃了编号为:1的苹果!
小B吃了编号为:-1的苹果!
小A吃了编号为:0的苹果!

这两种结果会导致多想访问统一资源的安全问题!

重点:继承方式和实现方式的区别:

继承方式:

1)Java中类是单继承的,如果继承了Thread类,该类就不能再有其他的直接父类;

2)从操作上分析,继承方式更加简单,获取线程名称简单!(操作简单);

3)从多线程共享同一资源上分析,继承Thread类方式一是不能实现资源的共享,但是方式二是可以实现的(本质上Thread类也实现类Runnable接口)

实现方式:

1)Java中类可以实现接口,此时该类还可以继承其他的类,并且还可以实现其他的接口(设计上更加优雅和优秀);

2)从操作上分析,实现方式稍微有点复杂,获取线程的名称也比较复杂,得使用ThreadcurrentThread()来获取当前的线程,进而获取线程的名称;

3)从多线程共享同一资源上分析,实现接口可以做到多个线程共享资源!(是否共享同一个资源);

4)默认的Thread.run()就是直接调用内部的Runabble接口,因此使用Runnable接口告诉线程该做什么,比较合理。


下一篇对应此例子,实现多线程访问共同资源的安全问题:http://blog.csdn.net/super_yc/article/details/73294203



猜你喜欢

转载自blog.csdn.net/super_yc/article/details/73195945