多线程
概念
-
同步
先做1,1做完了再做2
-
异步
两件事可以一起做
-
并行
在一个CPU核心上只运行一件事
-
并发
在一个CPU核心上运行多件事,利用CPU时间切片技术
-
多进程
进程与进程之间,内存不共享 运行一个应用程序,就是启动了一个进程,这个刚刚启动的进程,叫做主进程 由主进程创建的进程,叫做子进程
-
多线程
线程与线程之间,内存共享(方法区和堆区共享) 只要有进程,每个进程里面,都默认有一个线程,此线程叫做主线程 由主线程创建的线程,叫做子线程
-
多协程
-
-
快速入门
-
Thread.sleep()在当前线程睡眠,单位为毫秒
-
Thread::start启动线程
-
Thread::run线程在执行时,要运行的代码
-
SecondThread.java
package com.futureweaver.multithread;
public class SecondThread extends Thread {
@Override
public void run() {
try {
while (true) {
System.out.println("第二个线程的代码");
Thread.sleep(1500);
}
} catch (InterruptedException e) {
System.out.println("第二个线程退出了...");
}
}
}
- ThreadPractice.java
package com.futureweaver.multithread;public class ThreadPractice {
public static void main(String[] args) throws InterruptedException {
Thread thread = new SecondThread();
thread.start();while (true) {
System.out.println("主线程里面的代码");// InterruptedException异常为别人想要关闭此线程
// 在运行此代码时,会收到一个异常
// 抓此异常,目的是为了释放掉自己所占用的资源
// 抛此异常,目的是不做任何处理,直接退出程序
// 当前线程睡眠多少毫秒
Thread.sleep(2000);
}
}
}
使用时的注意事项
每创建一个线程,都要有名字
Thread结合Runnable的用法
在使用线程时,应注意关注点分离,Thread只用于处理创建线程、在线程里执行过程等等的功能 Runnable只关注要干什么 关注点分离的好处在于,无需重度重写父类的方法,就可以直接用
- SecondRunnable.java
package com.futureweaver.multithread;
public class SecondRunnable implements Runnable {
@Override
public void run() {
try {
while (true) {
System.out.println("这是一个Thread结合Runnable要执行的代码");
Thread.sleep(1500);
}
} catch (InterruptedException e) {
System.out.println("线程退出...");
}
}
}
- Thread2Practice.java
package com.futureweaver.multithread;// 多线程的第二种用法
// Thread结合Runnable使用public class Thread2Practice {
public static void main(String[] args) throws InterruptedException {
SecondRunnable secondRunnable = new SecondRunnable();
Thread thread = new Thread(secondRunnable, "thread and runnable ...");
thread.start();while (true) {
System.out.println("主线程代码");
Thread.sleep(2000);
}
}
}
Runnable的匿名内部类的用法
- Thread2Practice.java
package com.futureweaver.multithread;// 多线程的第二种用法
// Thread结合Runnable使用public class Thread2Practice {
public static void main(String[] args) throws InterruptedException {
Runnable secondRunnable = new Runnable() {
@Override
public void run() {
try {
while (true) {
System.out.println("second runnable里的过程");
Thread.sleep(1500);
}
} catch (InterruptedException e) {
System.out.println("线程退出了");
}
}
};
Thread thread = new Thread(secondRunnable, "thread and runnable ...");
thread.start();while (true) {
System.out.println("主线程代码");
Thread.sleep(2000);
}
}
}
Runnable的lambda表达式写法【重点】
- Thread2Practice.java
package com.futureweaver.multithread;// 多线程的第二种用法
// Thread结合Runnable使用public class Thread2Practice {
public static void main(String[] args) throws InterruptedException {
// 匿名内部类,缺什么方法,就重写什么方法即可
// lambda表达式必须是函数式接口// public void run() {...}
// public是能够智能识别的
// void是能够智能识别
// ()说明的是函数式接口当中的函数没有任何参数,假设有参数,参数类型都不用写,因为可以智能识别
// ->用于分隔参数和函数体/方法体
// {}方法体
// 方法体内,如果函数式接口当中的函数需要返回值,那就写return语句
// 如果返回值类型为void,那就不写return语写
Thread thread = new Thread(() -> {
try {
while (true) {
System.out.println("second runnable里的过程");
Thread.sleep(1500);
}
} catch (InterruptedException e) {
System.out.println("线程退出了");
}
}, "thread and runnable ...");
thread.start();while (true) {
System.out.println("主线程代码");
Thread.sleep(2000);
}
}
}
注意
- 主线程退出,其他线程不管有没有执行结束,都会结束
- 当多个线程同时使用一个资源时,极有可能会出现线程同步问题: 当多个线程同时争抢一个资源时,操作此资源的代码如果无法保证原子性(类似于数据库中的事务),就会产生数据错乱问题 为了保证数据是对的,或保证数据的一致性,需要在操作此资源时添加线程同步的机制 推荐使用synchronized关键字来保证此机制
线程同步操作演示
- SecondRunnable.java
package com.futureweaver.threadsync;import java.util.ArrayList;
import java.util.List;public class SecondRunnable implements Runnable {
private List<String> list;public SecondRunnable(List<String> list) {
this.list = list;
}@Override
public void run() {
try {
for (int i = 20000; i < 21000; i++) {
Thread.sleep(1);
add(list, Integer.toString(i));
}
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
// syncrhonized关键字能够保证在操作此list时,不会发生资源争抢问题
public static synchronized void add(List<String> list, String str) {
// 开始
list.add(str);
// 结束
}
}
- ThreadPractice.java
package com.futureweaver.threadsync;import java.util.ArrayList;
import java.util.List;public class ThreadPractice {
public static void main(String[] args) throws InterruptedException {
List<String> list = new ArrayList<>();
SecondRunnable secondRunnable = new SecondRunnable(list);
Thread thread = new Thread(secondRunnable);
thread.start();for (int i = 0; i < 10000; i++) {
Thread.sleep(1);
String s = Integer.toString(i);
SecondRunnable.add(list, s);
}
Thread.sleep(5000);
System.out.println(list);
}
}
死锁问题
所谓死锁问题,就是在等待一把永远也解不开的锁
死锁案例1
加锁后出现异常,导致锁无法解开
- SecondRunnable.java
package com.futureweaver.threadsync;import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;public class SecondRunnable implements Runnable {
private List<String> list;// 注意,如果多个线程同时操作某个资源
// 那么想要用Lock加线程同步,必须要保证这几个线程用的是同一把锁
public static Lock lock = new ReentrantLock();public SecondRunnable(List<String> list) {
this.list = list;
}@Override
public void run() {
try {
for (int i = 20000; i < 21000; i++) {
Thread.sleep(1);
add(list, Integer.toString(i));
}
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}public static void add(List<String> list, String str) {
// 将这一把锁上锁
lock.lock();// 开始
list.add(str);
// 结束list.get(30000);
// 将这一把锁解锁
lock.unlock();
}
}
- ThreadPractice.java
package com.futureweaver.threadsync;import java.util.ArrayList;
import java.util.List;public class ThreadPractice {
public static void main(String[] args) throws InterruptedException {
List<String> list = new ArrayList<>();
SecondRunnable secondRunnable = new SecondRunnable(list);
Thread thread = new Thread(secondRunnable);
thread.start();for (int i = 0; i < 10000; i++) {
Thread.sleep(1);
String s = Integer.toString(i);
SecondRunnable.add(list, s);
}
Thread.sleep(5000);
System.out.println(list);
}
}
死锁案例二
小明锁了A,等待B。同时B被小红锁上,等待A
- XiaoHong.java
package com.futureweaver.threadsync;import java.util.concurrent.locks.Lock;
public class XiaoHong implements Runnable {
private Lock left;
private Lock right;public XiaoHong(Lock left, Lock right) {
this.left = left;
this.right = right;
}@Override
public void run() {
right.lock();
System.out.println("小红拿到第二根筷子");left.lock();
System.out.println("小红拿到第一根筷子");System.out.println("吃饭");
left.unlock();
right.unlock();
}
}
- XiaoMing.java
package com.futureweaver.threadsync;import java.util.concurrent.locks.Lock;
public class XiaoMing implements Runnable {
private Lock left;
private Lock right;public XiaoMing(Lock left, Lock right) {
this.left = left;
this.right = right;
}@Override
public void run() {
left.lock();
System.out.println("小明拿到了第一根筷子");right.lock();
System.out.println("小明拿到了第二根筷子");System.out.println("吃饭");
right.unlock();
left.unlock();
}
}
- DoubleLockDeadPractice.java
package com.futureweaver.threadsync;import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;public class DoubleLockDeadPractice {
public static void main(String[] args) {
Lock left = new ReentrantLock();
Lock right = new ReentrantLock();Thread xiaohong = new Thread(new XiaoHong(left, right));
Thread xiaoming = new Thread(new XiaoMing(left, right));
xiaohong.start();
xiaoming.start();
}
}
浙公网安备 33010602011771号