多线程
程序:程序是一段指令集和,是静态的。
进程:当一个程序正在执行时,对应一个进程。
进程由程序、数据和PCB(Process Control Block)组成,是操作系统 资源分配和调度的独立单位
线程:为了进一步改善资源利用率、提高系统运行效率而引入的机制。 在一个进程中,多个并行的线程分别执行不同的任务,能更有效的利 用系统资源,提高程序运行效率。
==线程==是进程中的一个相对独立的指令序列,它也可被操作系统独立调 度。
==多线程==就是指一个进程中有多个正在运行中的且可被独立调度的指令 序列
线程和进程都拥有对应的执行控制结构。但==线程是从属于某个进程的, 它只能使用所属进程的内存资源==。
==进程内部的多个线程之间共享该进程的地址空间和资源==。 ==每个线程有独立的线程栈==。
线程和进程的关系: 一个进程可以包含多个线程,而一个线程只能属于某一个进程,线程不能 脱离进程而独立运行;
每一个进程至少包含一个线程(称为主线程);
java程序的入口main()方法就 是在主线程中被执行的。 在主线程中可以创建并启动其它的线程;
一个进程内的所有线程共享该进程的内存资源。
创建多线程的方式:
继承Thread类:
创建Thread类的子类,在子类中重写run()方法。
可使用Thread类的构造器Thread(String name)为新线程指定名称。
调用start()方法启动新线程。
java.lang.Thread类封装了“线程”的功能。
Thread类的实例代表一个线程对象,借助该实例可以启动和管理一个线 程。
==Thread类的构造函数==
public Thread()
public Thread(String name) //参数name代表线程名
public Thread(Runnable target) //参数target为可运行的对象
==Thread类中的方法:==
public void start() //启动线程
public void run() //线程的进入点。通过定义Thread类的子类,并重写 run()方法以提供子线程要执行的功能。
public final String getName() //线程名
==Thread类中的两个静态方法==
public static void sleep(long millis) //使得当前线程休眠指定的时间
public static Thread currentThread() //返回当前线程对象
实现Runnable接口创建线程:
Thread类的构造函数:
public Thread(Runnable target)
public Thread(Runnable target, String name)
==Runnable中只有一个run();方法,实现Runnable的对象必须放在Thread中使用==
使用Thread和Runnable的区别:
- extends Thread 的话,有一个java局限性,java是单继承,如果一个类继承了Thread,就不能继承其他的类了
- implements Runnable 的话,首先是通过实现接口实现,一个类可以实现多个接口,即这个类既然可以作为作为可以被线程执行的目标对象之外,还可以给这个类添加其他的类(即实现多个接口)。
extends Thread创建线程:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30
|
public class MultiThreadingDemo01 extends Thread{
@Override public void run() { super.run(); System.out.println("启动MultiThreadingDemo01的线程"); } }
public class MultiThreadingDemo01Test { public static void main(String[] args) { MultiThreadingDemo01 myThread01 = new MultiThreadingDemo01(); MultiThreadingDemo01 myThread02 = new MultiThreadingDemo01(); myThread01.start(); myThread02.start(); } }
|
implements Runnable创建线程:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
|
public class MultiThreadRunnable implements Runnable{
@Override public void run() { System.out.println("this is Runnable Thread"); } }
public class MultiThreadRunnableTest { public static void main(String[] args) { Thread myThread = new Thread(new MultiThreadRunnable()); myThread.start(); } }
|
使用匿名内部类创建线程:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| public class MyThread02 extends Thread{
public static void main(String[] args) { for (int i = 0;i < 10;i++){ new Thread(new Runnable() { @Override public void run() { System.out.println(Thread.currentThread().getName()); } },"this name is " + i).start(); }
} }
|
线程创建计时器:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38
|
public class MultiThreadTimer extends Thread{
@Override public void run() { super.run(); int i = 0; while(1 == 1){ System.out.println("计时器:" + i); i++; try { sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } } } }
public class MultiThreadTimerTest { public static void main(String[] args) { MultiThreadTimer myThreadTimer = new MultiThreadTimer(); myThreadTimer.start(); } }
|
线程中的方法:
currentThread() : 获取当前线程对象;
在Thread类中定义了三个优先级常量:MIN_PRIORITY, MAX_PRIORITY 和NORM_PRIORITY,其值分别为1, 10, 5。
setPriority(int xxx) : 设置线程优先级,级别为1-10,10为优先级最高,优先级高并不是先执行,只是增加抢占到资源的机会。如果没有 为线程分配优先级,==默认为NORM_PRIORITY==。
Java采用==抢占式调度方式==,即高优先级线程具有剥夺低优先级线程执 行的权力。 如果一个低优先线程正在执行,这时出现一个高优先级线程,那么低 优先级线程就被停止执行,放弃CPU,退回到等待队列中,让高优先 级线程立即执行。 如果多个线程具有相同的优先级,则按”==先来先服务==”的原则调度。
Thread类中的==static yield()==方法用来让==当前线程主动放弃CPU==,将执 行的机会让给了下一个同级别的线程。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41
| public class MultiThreadDemo02 extends Thread{
public MultiThreadDemo02(String name) { super(name); }
@Override public void run() { super.run(); System.out.println("执行了线程对象" + Thread.currentThread().getName()); } }
public class MultiThreadDemo02Test { public static void main(String[] args) { MultiThreadDemo02 myThread021 = new MultiThreadDemo02("线程1"); MultiThreadDemo02 myThread022 = new MultiThreadDemo02("线程2"); MultiThreadDemo02 myThread023 = new MultiThreadDemo02("线程3"); MultiThreadDemo02 myThread024 = new MultiThreadDemo02("线程4");
myThread021.setPriority(10); myThread024.setPriority(10); myThread021.yield(); myThread022.setPriority(Thread.MIN_PRIORITY); myThread023.setPriority(Thread.currentThread().MIN_PRIORITY);
myThread021.start(); myThread022.start(); myThread023.start(); myThread024.start(); } }
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48
| public class MultiThreadDemo03 extends Thread { public MultiThreadDemo03(String name) { super(name); }
@Override public void run() { super.run(); try { Thread.sleep(5000); } catch (InterruptedException e) { e.printStackTrace(); }
System.out.println("线程" + Thread.currentThread().getName() + "执行结束"); } }
public class MultiThreadDemo03Test { public static void main(String[] args) { MultiThreadDemo03 multiThreadDemo031 = new MultiThreadDemo03("1111"); MultiThreadDemo03 multiThreadDemo032 = new MultiThreadDemo03("2222");
multiThreadDemo031.start(); multiThreadDemo032.start();
try { multiThreadDemo031.join(); multiThreadDemo031.join(); } catch (InterruptedException e) { e.printStackTrace(); }
System.out.println("程序结束");
} }
|
终止线程:
==interrupt() :终止线程==
==isInterrupted() : 获取当前线程是否终止==
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
| public class MyThread03 extends Thread{ @Override public void run() { super.run(); int i = 0;
while(true){ System.out.println("thread:" + i++); if (Thread.currentThread().isInterrupted()){ System.out.println("线程终止!"); break; } } } }
public class MyThread03Test { public static void main(String[] args) throws InterruptedException { MyThread03 myThread03 = new MyThread03(); myThread03.start();
Thread.sleep(20); myThread03.interrupt(); } }
|
同步锁
给代码块加锁:(锁定某个对象)
1 2 3
| synchronized (){ ... }
|
给方法加锁:
1
| public synchronized void method(){ ...}
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56
| public class Bank { String account; double balance; public Bank(String account,double balance){ this.account = account; this.balance = balance; } public void drawAccount(String name) throws InterruptedException { synchronized(this){ this.balance = this.balance - 200; Thread.sleep(100); System.out.println(name + "取款200 账户余额: " + this.balance); } } } public class MyThread extends Thread { String name; public MyThread(String name) { this.name = name; } static Bank bank = new Bank("1001",2000); @Override public void run() { super.run(); while (1 == 1){ if (bank.balance >= 200){ try { bank.drawAccount(this.name); Thread.sleep(100); } catch (InterruptedException e) { e.printStackTrace(); } }else{ System.out.println("余额不足!!!!"); break; } } } }
public class Test { public static void main(String[] args) { MyThread mt1 = new MyThread("张三"); MyThread mt2 = new MyThread("李四"); MyThread mt3 = new MyThread("王五"); mt1.start(); mt2.start(); mt3.start(); } }
|
死锁:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57
|
public class MyThread04 extends Thread{ String name; static Object obj1 = new Object(); static Object obj2 = new Object(); public MyThread04(String name) { this.name = name; } @Override public void run() { super.run(); if("线程1".equals(this.name)){ synchronized(obj1){ System.out.println(this.name + "锁定了资源obj1"); try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } synchronized(obj2){ System.out.println(this.name + "锁定了资源obj2"); } } } if("线程2".equals(this.name)){ synchronized(obj2){ System.out.println(this.name + "锁定了资源obj2"); try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } synchronized(obj1){ System.out.println(this.name + "锁定了资源obj1"); } } } } }
public class MyThread04Test { public static void main(String[] args) { MyThread04 mt1 = new MyThread04("线程1"); MyThread04 mt2 = new MyThread04("线程2"); mt1.start(); mt2.start(); } }
|
线程间通信:
多个线程之间需要协同完成工作,就需要线程之间进行通信。
wait()用于让当前线程失去操作权限,当前线程进入等待序列
notify()用于随机通知一个持有对象的锁的线程获取操作权限
notifyAll()用于通知所有持有对象的锁的线程获取操作权限
wait(long) 和wait(long,int)用于设定下一次获取锁的距离当前释放锁的时间间隔
在使用的时候要求==在synchronize语句中使用==
wait() : 让当前线程等待,知道另一个线程调用此对象的notify() 或者调用此对象的 notifyAll() 方法,或者指定的时间以过。当前线程必须锁定此对象
notify() : 唤醒正在等待对象的单个线程。换新的线程将以通常的方式争夺此对象资源;
notifyAll() : 唤醒正在等待对象的所有线程。
包子铺生产包子,消费者吃包子的问题:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58
|
public class Bun02 { private String skin; private String fill; private boolean flag; private int count = 0; private String[] skins = {"白皮","绿皮"}; private String[] fills = {"韭菜馅","大葱馅"}; public Bun02() { } public String[] getSkins() { return skins; } public String[] getFills() { return fills; } public static int getVOLUME() { return VOLUME; } public int getCount() { return count; } public void setCount(int count) { this.count = count; } public String getSkin() { return skin; } public void setSkin(String skin) { this.skin = skin; } public String getFill() { return fill; } public void setFill(String fill) { this.fill = fill; } public boolean isFlag() { return flag; } public void setFlag(boolean flag) { this.flag = flag; } }
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59
|
public class Producer02 extends Thread{ private Bun02 bun02; public Producer02(String name,Bun02 bun02) { super(name); this.bun02 = bun02; } @Override public void run() { super.run(); while(true){ synchronized(bun02){ if (!bun02.isFlag()){ if (bun02.getCount() % 2 == 0){ bun02.setSkin(bun02.getSkins()[0]); bun02.setSkin(bun02.getFills()[0]); System.out.println(Thread.currentThread().getName() + "生产了" + bun02.getSkins()[0] + bun02.getFills()[0] + "的包子"); System.out.println("生产了" + (bun02.getCount() + 1) + "个包子了"); }else{ bun02.setSkin(bun02.getSkins()[1]); bun02.setSkin(bun02.getFills()[1]); System.out.println(Thread.currentThread().getName() + "生产了" + bun02.getSkins()[1] + bun02.getFills()[1] + "的包子"); System.out.println("生产了" + (bun02.getCount() + 1) + "个包子了"); } bun02.setCount(bun02.getCount() + 1); try { Thread.sleep(2000); } catch (InterruptedException e) { e.printStackTrace(); } if (bun02.getCount() >= bun02.getVOLUME()){ bun02.setFlag(true); System.out.println("包子生产结束!!快来吃吧"); bun02.notify(); } }else { try { bun02.wait(); } catch (InterruptedException e) { e.printStackTrace(); } } } } } }
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58
|
public class Consumer02 extends Thread{ private Bun02 bun02; public Consumer02(String name,Bun02 bun02) { super(name); this.bun02 = bun02; } @Override public void run() { super.run(); while(true){ synchronized(bun02){ if (bun02.isFlag()){ if (bun02.getCount() % 2 == 0){ bun02.setCount(bun02.getCount() - 1); System.out.println(Thread.currentThread().getName() + "吃了" + bun02.getSkins()[0] + bun02.getFills()[0] + "的包子"); System.out.println("剩下" + bun02.getCount() + "个包子了"); }else{ bun02.setCount(bun02.getCount() - 1); System.out.println(Thread.currentThread().getName() + "吃了" + bun02.getSkins()[1] + bun02.getFills()[1] + "的包子"); System.out.println("剩下" + bun02.getCount() + "个包子了"); } try { Thread.sleep(2000); } catch (InterruptedException e) { e.printStackTrace(); } if (bun02.getCount() == 0){ bun02.setFlag(false); System.out.println("包子吃完了,在来几个吧"); bun02.notify(); } }else { try { bun02.wait(); } catch (InterruptedException e) { e.printStackTrace(); } } } } } }
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
|
public class Bun02Test { public static void main(String[] args) { Bun02 bun = new Bun02(); Producer02 producer01 = new Producer02("李阿姨",bun); producer01.start(); Producer02 producer02 = new Producer02("王阿姨",bun); producer02.start(); Consumer02 consumer01 = new Consumer02("张三",bun); consumer01.start(); Consumer02 consumer02 = new Consumer02("李四",bun); consumer02.start(); } }
|
线程池:
对于更复杂的任务来说这种频繁手动式的创建、管理线程显然是不可取的,因为线程对象使用了大量的内存,在大规模应用程序中,创建、分配和释放多线程对象会产生大量内存管理开销。为此,可以考虑使用Java提供的线程池来创建多线程,进一步优化线程管理。
==Executor接口==实现线程池管理
步骤:
- 创建一个实现Runnable接口或者Callable接口的实现类,同时重写run()或者call()方法;
- 创建Runnable接口或者Callable接口的实现类对象;
- 使用Executors线程执行器类创建线程池;
- 使用ExecutorService执行器服务类的submit()方法将Runnable接口或者Callable接口的实现类对象提交到线程池进行管理;
- 线程任务执行完成后,可以使用shutdown()方法关闭线程池。
Executors创建线程池的方法
方法声明 |
功能描述 |
ExecutorService newCachedThreadPool() |
创建一个==可扩展线程池的执行器==。这个线程池执行器适用于启动许多短期任务的应用程序 |
ExecutorService newFixedThreadPool(int nThreads) |
创建一个==固定线程数量线程池的执行器==。这种线程池执行器可以很好的控制多线程任务,也不会导致由于响应过多导致的程序崩溃 |
ExecutorServicenewSingleThreadExecutor() |
在特殊需求下创建一个==只执行一个任务的单个线程== |
ScheduledExecutorService newScheduledThreadPool(int corePoolSize) |
创建一个==定长线程池,支持定时及周期性任务执行== |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| public class RunnableImp implements Runnable{ @Override public void run() { System.out.println(Thread.currentThread().getName() + "执行一个线程任务"); } } public class ThreadPool { public static void main(String[] args) { ExecutorService executor = Executors.newFixedThreadPool(2); executor.submit(new RunnableImp()); executor.submit(new RunnableImp()); executor.submit(new RunnableImp()); executor.shutdown(); executor.submit(new RunnableImp()); } }
|
CompletableFuture类实现线程池管理
CompletableFuture对象创建的四个静态方法:
方法声明 |
功能描述 |
static CompletableFuture runAsync(Runnable runnable) |
以Runnable函数式接口类型为参数,并使用ForkJoinPool.commonPool()作为它的线程池执行异步代码获取CompletableFuture计算结果为空的对象 |
static CompletableFuture runAsync(Runnable runnable, Executor executor) |
以Runnable函数式接口类型为参数,并传入指定的线程池执行器executor来获取CompletableFuture计算结果为空的对象 |
static CompletableFuture supplyAsync(Supplier supplier) |
以Supplier函数式接口类型为参数,并使用ForkJoinPool.commonPool()作为它的线程池执行异步代码获取CompletableFuture计算结果非空的对象 |
static CompletableFuture supplyAsync(Supplier supplier, Executor executor) |
以Supplier函数式接口类型为参数,并传入指定的线程池执行器executor来获取CompletableFuture计算结果非空的对象 |