Java多线程

多线程和单线程的区别:

单线程程序执行是顺序的,比如在一个聊天程序中,发送消息的时候不能接收消息,在接收消息的时候不能发送消息。

多线程程序各个线程看起来是并发的,在发送消息的时候可以同时接收消息。接收消息的同时可以发送消息。


多线程和多进程的区别:

首先看一下进程和线程的区别:

进程是程序在内存中的表现形式。是程序的执行环境,创建一个进程之后就自动创建了一个线程。一个进程中有一个到多个线程,所以进程是线程的容器。

多线程和多进程的区别:

每个进程拥有自己的一整套变量,而线程则共享数据,共享变量是的线程之间通讯更有效,更方便。


Java中创建线程有三种方式:

  • 方式1:继承Thread类
  • 方式2:实现Runnable接口
  • 方式3:实现Callable接口

首先创建一个类作为共享类:模拟人吃东西;

synchronized保证了每次只能有一个访问food对象。

/**
 * 共享类:
 * @author Z7M-SL7D2
 */
class Foods{
	Integer foodCount;

	public Foods(Integer foodCount) {
		super();
		this.foodCount = foodCount;
	}

	public Integer getFoodCount() {
		return foodCount;
	}

	public void setFoodCount(Integer foodCount) {
		this.foodCount = foodCount;
	}
	public void eatFood(){
		if(foodCount > 0)
			foodCount = foodCount - 1;
}
}

方式1:继承Thread类。

/**
 * 方式1:继承Thread类复写run方法,实现多线程
 * @author Z7M-SL7D2
 *
 */

class Person extends Thread{
	private Foods foods;
	public Person(Foods foods){
		this.foods = foods;
	}
	@Override
	public void run() {
		synchronized (foods) {
			while(this.foods.getFoodCount() > 0) {
				System.out.println(Thread.currentThread().getName() + "吃了一个,还剩下" + (this.foods.getFoodCount() - 1) + "个食物");
				this.foods.setFoodCount(this.foods.getFoodCount() - 1);
			}
		}
	}
}


public class Test {
	public static void main(String[] args) {
		Foods food = new Foods(5);
		Thread t  = new Person(food);
		t.start();
		Thread t1  = new Person(food);
		t1.start();
		Thread t2  = new Person(food);
		t2.start();
	}
}

方式二:实现Runnable接口

/**
 * 方式2:实现runnable接口
 * @author Z7M-SL7D2
 *
 */

class Person implements Runnable{
	private Foods foods;
	public Person1(Foods foods){
		this.foods = foods;
	}
	@Override
	public void run() {
		synchronized (foods) {
			while(this.foods.getFoodCount() > 0) {
				System.out.println(Thread.currentThread().getName() + "吃了一个,还剩下" + (this.foods.getFoodCount() - 1) + "个食物");
				this.foods.setFoodCount(this.foods.getFoodCount() - 1);
			}
		}
	}
}

public class Test {
	public static void main(String[] args) {
		System.out.println(Thread.currentThread().getName() + "线程启动");
		Foods food = new Foods(5);
		Person p = new Person(food);
		Thread thread = new Thread(p);
		thread.start();
		Thread thread1 = new Thread(p);
		thread1.start();
	}
}

实现Runnable接口,使用Lamda表达式:

/**
 * 方式2:实现runnable接口,使用Lamdam表达式
 * @author Z7M-SL7D2
 *
 */
public class Test {
	public static void main(String[] args) {
		Foods foods = new Foods(5);
		Thread thread = new Thread(()->{
			synchronized (foods) {
				while(foods.getFoodCount() > 0) {
					System.out.println(Thread.currentThread().getName() + "吃掉一个还剩下" + (foods.getFoodCount() - 1));
					foods.setFoodCount(foods.getFoodCount() - 1);
				}
			}
		});
		thread.start();
	}
}

方式3:实现Callable接口

/**
 * 方式3:实现Callable接口
 * @author Z7M-SL7D2
 *
 */
class Person implements Callable<String>{
	Foods food;
	public Person(Foods food) {
		this.food = food;
	}
	@Override
	public String call() throws Exception {
		synchronized (food) {
			while(food.getFoodCount() > 0) {
				food.eatFood();
				System.out.println(Thread.currentThread().getName() + "吃了一个,还剩下" + food.getFoodCount());
			}
		}
		
		return "吃完了";
	}
}


public class Test {
	public static void main(String[] args) {
		Foods foods = new Foods(5);
		FutureTask f = new FutureTask(new Person(foods));
		
		Thread t = new Thread(f);
		t.start();
		
		Thread t1 = new Thread(f);
		t1.start();
		
		
		Thread t2 = new Thread(f);
		t2.start();
		
		try {
			System.out.println(f.get());
		} catch (InterruptedException e) {
			e.printStackTrace();
		} catch (ExecutionException e) {
			e.printStackTrace();
		}
		
	}
}

Java线程的启动过程:

  1. 首先Thread类注册本地方法供Thread类使用(如:start0() 和stop0())。
  2. 对象调用start方法,
  3. start方法有调用start0()这个本地方法(原生系统函数)。
  4. 调用start方法之后会设置started为true,同一Thread对象再次调用会抛出异常。
  5. 然后通过start0回调run方法。

Runnable和Thread实现的区别:

  1. 继承自Thread就无法继承其他类,而实现Runnable接口之后还可以继承其他类。
  2. Java多线程处理上使用的是代理设计模式,所以使用Runnable实现的多线程的程序类可以更好的描述出程序共享的概念。

实现Runnable接口的负责处理核心业务,Thread负责,资源调度,以及一些线程操作。


线程5种状态之间的转换:


生产者消费者(wait / notifyAll):

同步代码块应该尽可能写到循环里面,不然就会出现同一时间一个线程把产品消费完的情况,

package 多线程;

class Foods {
	private int foodCount;

	public void eatFood() {
		if (foodCount > 0)
			this.foodCount -= 1;
	}

	public void productFood() {
		this.foodCount += 1;
	}

	public int getFoodCount() {
		return foodCount;
	}

	public Foods(int foodCount) {
		this.foodCount = foodCount;
	}
}

class Consumer implements Runnable {
	private Foods food;
	
	public Consumer(Foods food) {
		this.food = food;
	}

	@Override
	public void run() {
		while (true) {
			consume();
		}
	}

	public void consume() {
		synchronized (food) {
			if (food.getFoodCount() <= 0) {
				System.out.println("没产品可以消费");
				try {
					food.wait();
				} catch (InterruptedException e) {
					e.printStackTrace();
				}
				return;
			}

			food.eatFood();
			System.out.println(Thread.currentThread().getName() + "吃掉一个产品当前库存:" + food.getFoodCount());
			food.notifyAll();
		}
	}
}

class Productor implements Runnable {
	private Foods food;
	public static int MAX_COUNT;
	
	public Productor(Foods food) {
		this.food = food;
	}
	@Override
	public void run() {
		while (true) {
			product();
		}
	}

	public void product() {
		synchronized (food) {
			if (food.getFoodCount() >= MAX_COUNT) {
				System.out.println("不能再生产了,库存满了!");
				try {
					food.wait();
				} catch (InterruptedException e) {
					e.printStackTrace();
				}
				return;
			}

			if(food.getFoodCount() >= 10) {
				try {
					// 让其他线程有机会执行,但是不释放锁,所以此句在这儿无作用
					Thread.yield();
					
					//释放锁
					food.wait();
					} catch (Exception e) {
					e.printStackTrace();
				}
			}
			food.productFood();
			
			System.out.println("生产出一个产品,当前库存:" + food.getFoodCount());
			food.notifyAll();
		}
	}
	
	public int getFoodCount() {
		return food.getFoodCount();
	}
}

class ThreadJoin implements Runnable{
	private Foods food;
	private Thread pro;
	private Thread con;
	
	public ThreadJoin(Foods food, Thread pro, Thread con) {
		this.food = food;
		this.pro = pro;
		this.con = con;
	}
	
	@Override
	public void run() {
			while(true) {
				if(food.getFoodCount() > 10) {
					System.out.println("进入");
					try {
						con.join();
					} catch (InterruptedException e) {
						e.printStackTrace();
					}
				}
			}
		}
		
}

public class Test {
	public static void main(String[] args) {
		Foods food = new Foods(0);
		Productor.MAX_COUNT = 100;

		Productor p = new Productor(food);
		Consumer c = new Consumer(food);

		Thread productor = new Thread(p);

		Thread consumer1 = new Thread(c, "消费者1");

		Thread consumer2 = new Thread(c, "消费者2");

		Thread consumer3 = new Thread(c, "消费者3");
		
		ThreadJoin tJoin = new ThreadJoin(food, productor, consumer1);
		Thread thread = new Thread(tJoin);
		thread.setDaemon(true);

		productor.start();
		thread.start();
		consumer1.start();
		consumer2.start();
		consumer3.start();
		
		
			
	}
}

运行结果:







评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值