多线程的基本知识
接下来就不多说废话了,今天对多线程的知识来聊聊:
一、并发和并行:用下面这张图就可以解释了
二、进程和线程(这里就简单介绍一点,我主要是用代码讲解):
进程:一个内存中运行的应用程序
线程:线程是进程中的一个执行单元,负责当前进程中程序的执行,一个进程中至少有一个线程
三、线程也是一种对象,线程的创建有两种方式:Runnable接口或者继承了Thread类的对象才能成为线程
继承Thread类:
1. 定义Thread类的子类,并重写该类的run()方法,该run()方法的方法体就代表了线程需要完成的任务,因此把 run()方法称为线程执行体。
2. 创建Thread子类的实例,即创建了线程对象
3. 调用线程对象的start()方法来启动该线程,执行run方法
代码实列:
1 public class MyThread extends Thread{ 2 //定义指定线程的构造方法 3 public MyThread(String name) { 4 //super关键字调用父类参数的构造方法 5 super(name); 6 } 7 //重写run方法,完成此线程执行的任务 8 @Override 9 public void run() { 10 for (int i=0;i<6;i++){ 11 System.out.println(getName()+"正在执行"+i); 12 } 13 } 14 }
测试类:
1 public class Demo1 { 2 public static void main(String[] args) { 3 //有参构造函数初始化 4 MyThread myThread =new MyThread("新线程!"); 5 myThread.start();//启动线程 6 //在main方法中执行循环 7 for (int i=0;i<6;i++){ 8 System.out.println("子线程执行"+i); 9 } 10 } 11 }
运行结果:
实现Runnable接口
1. 定义Runnable接口的实现类,并重写该接口的run()方法,该run()方法的方法体同样是该线程的线程执行体。
2. 创建Runnable实现类的实例,并以此实例作为Thread的target来创建Thread对象,该Thread对象才是真正 的线程对象。
3. 调用线程对象的start()方法来启动线程。
代码实现:
public class MyRunnable implements Runnable {
@Override
public void run() {
for (int i=0;i<6;i++){
Thread thread = Thread.currentThread();
String name = thread.getName();
System.out.println(name+"\t"+i);
}
}
}
测试代码:
1 public class Demo1 { 2 public static void main(String[] args) { 3 //创建自定义类对象 线程任务对象 4 MyRunnable runnable = new MyRunnable(); 5 Thread thread = new Thread(runnable,"张三"); 6 thread.start();//启动线程 7 for (int i=0;i<6;i++){ 8 System.out.println("李四"+i); 9 } 10 } 11 }
运行结果:
实际上所有的多线程代码都是通过运行Thread的start()方法来运行的。因此,不管是继承Thread类还是实现Runnable接口来实现多线程,最终还是通过Thread的对象来控制线程的,熟悉Thread类的常用方法是进行多线程编程的基础。
如果一个类继承Thread,则不适合资源共享。但是如果实现了Runable接口的话,则很容易的实现资源共享。
总结:实现Runnable接口比继承Thread类所具有的优势:
1. 适合多个相同的程序代码的线程去共享同一个资源。
2. 可以避免java中的单继承的局限性。
3. 增加程序的健壮性,实现解耦操作,代码可以被多个线程共享,代码和线程独立。
4. 线程池只能放入实现Runable或Callable类线程,不能直接放入继承Thread的类。
四、线程安全
如果有多个线程在同时运行,而这些线程可能会同时运行这段代码。程序每次运行结果和单线程运行的结果是一样的,而且其他的变量的值也和预期的是一样的,就是线程安全的。
事例分析:电影院要卖票,我们模拟电影院的卖票过程。假设要播放的电影是 “喜羊羊与灰太狼”,本次电影的座位共100个。 我们来模拟电影院的售票窗口,实现多个窗口同时卖 “喜羊羊与灰太狼”这场电影票(多个窗口一起卖这100张票) 需要窗口,采用线程对象来模拟;需要票,Runnable接口子类来模拟。
代码实现:
1 public class Ticket implements Runnable { 2 private int ticket =10; 3 //创建一个锁对象 4 Object obj = new Object(); 5 @Override 6 public void run() { 7 //每个窗口卖票的操作 8 //窗口 永远开启 9 while (true){ 10 synchronized (obj) { 11 if (ticket > 0) {//有票 可以卖 12 //出票操作 13 //使用sleep模拟一下出票时间 14 try { 15 Thread.sleep(1000); 16 } catch (InterruptedException e) { 17 e.printStackTrace(); 18 } 19 //获取当前线程对象的名字 20 System.out.println(Thread.currentThread().getName() + "正在卖" + ticket--); 21 } 22 } 23 } 24 } 25 }
测试类:
1 public class TicketTest { 2 public static void main(String[] args) { 3 //创建线程任务对象 4 Ticket ticket = new Ticket(); 5 //创建三个窗口对象 6 Thread thread1 = new Thread(ticket,"窗口1"); 7 Thread thread2 = new Thread(ticket,"窗口2"); 8 Thread thread3 = new Thread(ticket,"窗口3"); 9 //三个窗口同时卖票 10 thread1.start(); 11 thread2.start(); 12 thread3.start(); 13 } 14 }
输出结果: