0
点赞
收藏
分享

微信扫一扫

java线程的简单例子(Thread and runnable)

其实要了解java多线程只需要理解以下几个事情:
1) java.lang.Thraed类
2) java.lang.Runnable接口
3) synchronized关键字
4) wait(),.notify(), notifyAll();

That’s all.

[java.util.Thread类]
Jdk的线程实现类,只要继承这个类那么我们就可以实现自己的线程。
如果你想要继承这个类,主要需要重载run方法。

例如:

Java代码


Pubilc class MyThread {
	Pubilc MyThread() {
		Super();
	}

	Public void run() {
		System.out.println(“Hello world”);
	}
}




当你要是用它的时候


Java代码


Publi class ThreadTest {
	Public static void main(String[] args)  {
		MyThread app = new MyThread();
		App.start();
	}
}




当你运行这个方法的时候,就会打出Hello world.



[java.lang.Runnable接口]


因为继承Thread类就无法继承别的你想要变为线程的类,


所以java.lang.Runnable接口可以实现你的愿望



那么看下面的例子:


食物类:


Java代码

public class Food {
	private int foodNum = 0;

	public Food(int foodNum) {
		this.foodNum = foodNum;
	}
	
	public void setFoodNum(int foodNum) {
		this.foodNum = foodNum;
	}
	
	public int getFoodNum() {
		return this.foodNum;
	}
}



消费者类:


Java代码


public class Customer {
	private String name = "";

	public Customer(String name) {
		this.setName(name);
	}

	protected void setName(String name) {
		this.name = name;
	}

	protected String getName() {
		return this.name;
	}
}



消费者线程类:


Java代码


public class CustomerThread extends Customer implements Runnable {

	private Food food = null;

	public CustomerThread(Food food) {
		super("Customer");
		this.food = food;
	}

	public void run() {
		this.consume();
	}
	
	public void startConsume() {
		Thread thread = new Thread(this);
		thread.start();
	}

	private void consume() {
		int num = this.food.getFoodNum();
		num++;
		this.food.setFoodNum(num);
		System.out.println(this.getName() + " " + "consume food");
	}
}



生产者类:


Java代码


public class Productor {
	private String name = "";

	public Productor(String name) {
		this.name = name;
	}

	protected void setName(String name) {
		this.name = name;
	}

	protected String getName() {
		return this.name;
	}
}



消费者类:

Java代码

public class ProductorThread extends Productor implements Runnable {

	private Food food = null;
	
	public ProductorThread(Food food) {
		super("Productor");
		this.food = food;
	}

	
	public void run() {
		this.increase();
	}
	
	public void startIncrease() {
		Thread thread = new Thread(this);
		thread.start();
	}

	private void increase() {
		int num = this.food.getFoodNum();
		num--;
		this.food.setFoodNum(num);
		System.out.println(this.getName() + " " + "increase food");
	}
}




测试类:


Java代码

public class MainTest {
	public static void main(String[] args) {
		Food food = new Food(0);
		ProductorThread productor = new ProductorThread(food);
		productor.startIncrease();
		CustomerThread customer = new CustomerThread(food);
		customer.startConsume();
	}
}




上面代码主要模拟了生产者和消费者生产食物,消费食物的过程,


这里面先让生产者生产了1个食物,然后让消费者消费了1个食物。



主要是想说明我们自己实现的Runnable接口的类必须借助Thread类


才可以把它变成一个线程,如果不借助Thread类,即使我们实现了run()方法,


这个类的对象也不会是一个线程。


说白了,就是用Thread(Runnable thread)这个构造方法把我们实现的Runnable


街口的类传入,然后通过Thread的start方法,来调用我们的run方法,其实


我们实现的Runnable接口的类要想变为线程,是要通过Thread这个载体来实现。



但是上面的实现存在一个问题,我们并不能保证同一时间内只有一个


CustomerThread线程在消费,不能保证在同一时间只有一个ProductorThread


线程在生产。



所以我们引入了synchronized关键字



[synchronized关键字]


通过在CustomerThraed的consume方法和ProductorThread的increase


方法前面加入synchronized关键字就可以解决上面所说的问题。


改动后的方法为:


Java代码

private synchronized void consume() {
		int num = this.food.getFoodNum();
		num++;
		this.food.setFoodNum(num);
		System.out.println(this.getName() + " " + "consume food");
	}
	private synchronized void increase() {
		int num = this.food.getFoodNum();
		num--;
		this.food.setFoodNum(num);
		System.out.println(this.getName() + " " + "increase food");
	}



那么synchronized关键字到底是干什么用的呢?



就是进入到synchronized关键字所包含的代码块的线程


都会尝试获得对象的锁,等拿到对象的锁后就可以进去执行代码,


如果得不到,就在那里阻塞,等待其它线程释放锁,那么怎么用呢?



1)在方法前用synchronized关键字,如下:


Java代码


private synchronized void consume() {
		int num = this.food.getFoodNum();
		num++;
		this.food.setFoodNum(num);
		System.out.println(this.getName() + " " + "consume food");
	}




当线程进入到这个方法的时候,这个线程就会获得这个方法所在对象的锁,


那么其他的进程想要进入这个方法,首先尝试去获得这个方法所在对象的锁,


但是已经被前一个线程霸占了,所只能等待,当前一个线程把这段代码执行


完毕,那么后来的线程就可以获得这个对象锁了,当然它进去后又会把后面的


线程阻塞在外面等待。


这种方法等同于:


Java代码

private void consume() {
		synchronized(this) {
			int num = this.food.getFoodNum();
			num++;
			this.food.setFoodNum(num);
			System.out.println(this.getName() + " " + "consume food");
		}
	}




但是这种方法我们把整个对象都锁住了,其他线程想要执行这个类中的其它用


Synchronized方法声明的方法都不可以了,因为想要进入其它的synchronized


方法也要先获得这个对象的锁,所以这种方法比较霸道,我们不建议这么做,


所以出现了第二种方法。


2)声明一个临时的对象,让进入同一个方法的线程去获得这个临时对象的锁,


  那么获得这个临时对象的锁,并不是整个对象的锁,所以并不会锁住整个对象,


  当然也就避免了上面第一种所遇到的问题:


Java代码


private void consume() {
		Object lock = new Object();
		synchronized(lock) {
			int num = this.food.getFoodNum();
			num++;
			this.food.setFoodNum(num);
			System.out.println(this.getName() + " " + "consume food");
		}
	}



Obj是一个临时的对象,当多个线程进入到这个方法的时候都会尝试去获得这个


Obj对象的锁,谁先获得,谁就可以继续执行,否则阻塞在外面,等待前一个进程


结束执行synchronized内的代码,出了synchronized包含的代码块之后,


会马上自动释放对这个obj对象的锁。



[wait(), notify()和notifyAll()]


其实采用了上面的synchronized关键字之后,上面的代码还是有问题,


什么问题?


我们再来仔细分析一下Synchronzied关键字,


Synchronzied关键字对线程来说就是这么一回事:


1) 线程进入synchronized代码块:尝试获得对象锁


2) 线程出了synchronized代码块:释放对象锁


说白了,就是谁有锁,谁就可以继续干活,没有就得等。


加锁就是限制同一时间有多个线程同时去访问公共的资源。



但是问题也就来了,synchronized可以限制对公共的资源访问,


但是无法决定线程访问公共资源的顺序,所以引入了wait(),


Notify(), notifyAll 等原语来控制线程访问的顺序。


注意这3个原语是当前对象的方法,不是当前线程的方法。



那么让我们来看看这三个原语有什么用:


1) wait(): 使当前线程阻塞,释放它所获得的对象的锁


2) notify(): 通知虚拟机当前线程准备要释放它所获得的对象的锁,


               当调用了wait()方法或者当这个线程出了synchronized


               代码块之后,这两个动作就是释放了当前线程对对象的锁的持有,


               那么其它的被阻塞的线程又可以执行了。


3) notify(): 跟notify()没有什么大区别,notify是通知1个被阻塞的线程做准备,


               notifyAll()是通知所有被阻塞的线程做准备,至于哪个线程可以获得


               这个锁,那就看JVM的啦!



所以对于上面的生产者与消费者的例子,


正确的流程是,


如果消费者有东西可以消费,那么我们就让他消费,


如果还需要生产,还可以生产,那么我们就让生产者生产,


只需要修改CustomerThread类ProductorThread类,


Food类 MainTest类。


那么我们的最终代码如下:


CustomerThread类:


Java代码


public class CustomerThread extends Customer implements Runnable {

	private Food food = null;

	public CustomerThread(Food food) {
		super("Customer");
		this.food = food;
	}

	public void run() {
		this.consume();
	}
	
	public void startConsume() {
		Thread thread = new Thread(this);
		thread.start();
	}

	private void consume() {
		synchronized(food) {
			while(true) {
				if(food.getFoodNum() <= 0) {
					try {
						food.wait();
					} catch (InterruptedException e) {
						// Do nothing
					}
				} else {
					break;
				}
			}
			int num = this.food.getFoodNum();
			num--;
			this.food.setFoodNum(num);
			System.out.println(this.getName() + " " + "consume food " + num);
			food.notify();
		}
	}
}




ProductorThread类:


Java代码

public class ProductorThread extends Productor implements Runnable {

	private Food food = null;
	
	public ProductorThread(Food food) {
		super("Productor");
		this.food = food;
	}

	public void run() {
		this.increase();
	}
	
	public void startIncrease() {
		Thread thread = new Thread(this);
		thread.start();
	}

	private void increase() {
		synchronized(food) {
			while(true) {
				if(food.getFoodNum() == Food.MAX_NUM) {
					try {
						food.wait();
					} catch (InterruptedException e) {
						// Do nothing
					}
				} else {
					break;
				}
			}
			int num = this.food.getFoodNum();
			num++;
			this.food.setFoodNum(num);
			System.out.println(this.getName() + " " + "increase food " + num);
			food.notify();
		}
	}
}




Food类:


Java代码


public class Food {

	public static final int MAX_NUM = 10;

	private int foodNum = 0;

	public Food(int foodNum) {
		this.foodNum = foodNum;
	}

	public void setFoodNum(int foodNum) {
		this.foodNum = foodNum;
	}

	public int getFoodNum() {
		return this.foodNum;
	}
}




MainTest类:


Java代码


public class MainTest {
	public static void main(String[] args) {
		Food food = new Food(0);
		
		CustomerThread customer = new CustomerThread(food);
		customer.startConsume();
		CustomerThread customer1 = new CustomerThread(food);
		customer1.startConsume();
		CustomerThread customer2 = new CustomerThread(food);
		customer2.startConsume();
		CustomerThread customer3 = new CustomerThread(food);
		customer3.startConsume();
		CustomerThread customer4 = new CustomerThread(food);
		customer4.startConsume();
		CustomerThread customer5 = new CustomerThread(food);
		customer5.startConsume();
		
		ProductorThread productor = new ProductorThread(food);
		productor.startIncrease();
		ProductorThread productor1 = new ProductorThread(food);
		productor1.startIncrease();
		ProductorThread productor2 = new ProductorThread(food);
		productor2.startIncrease();
		ProductorThread productor3 = new ProductorThread(food);
		productor3.startIncrease();
		ProductorThread productor4 = new ProductorThread(food);
		productor4.startIncrease();
		ProductorThread productor5 = new ProductorThread(food);
		productor5.startIncrease();



	}
}




终于写完了,累死我了~~~



  • 多线程问题.rar (19.1 KB)
  • 描述: 这篇文档和对应的源代码
  • 下载次数: 35


 

举报

相关推荐

0 条评论