多线程和单线程的区别:
单线程程序执行是顺序的,比如在一个聊天程序中,发送消息的时候不能接收消息,在接收消息的时候不能发送消息。
多线程程序各个线程看起来是并发的,在发送消息的时候可以同时接收消息。接收消息的同时可以发送消息。
多线程和多进程的区别:
首先看一下进程和线程的区别:
进程是程序在内存中的表现形式。是程序的执行环境,创建一个进程之后就自动创建了一个线程。一个进程中有一个到多个线程,所以进程是线程的容器。
多线程和多进程的区别:
每个进程拥有自己的一整套变量,而线程则共享数据,共享变量是的线程之间通讯更有效,更方便。
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线程的启动过程:
- 首先Thread类注册本地方法供Thread类使用(如:start0() 和stop0())。
- 对象调用start方法,
- start方法有调用start0()这个本地方法(原生系统函数)。
- 调用start方法之后会设置started为true,同一Thread对象再次调用会抛出异常。
- 然后通过start0回调run方法。
Runnable和Thread实现的区别:
- 继承自Thread就无法继承其他类,而实现Runnable接口之后还可以继承其他类。
- 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();
}
}
运行结果: