Java核心类库篇7——多线程
2023-09-14 09:01:23 时间
Java核心类库篇7——多线程
1、程序、进程和线程
- 程序 - 数据结构 + 算法,主要指存放在硬盘上的可执行文件
- 进程 - 主要指运行在内存中的可执行文件
- 线程就是进程内部的程序流
操作系统内部支持多 进程的,而每个进程的内部又是支持多线程的
2、线程的创建
方法声明 | 功能介绍 |
---|---|
public Thread() | 使用无参的方式构造对象 |
public Thread(String name) | 根据参数指定的名称来构造对象 |
public Thread(Runnable target) | 根据参数指定的引用来构造对象,其中Runnable是个接口类型 |
public Thread(Runnable target, String name) | 根据参数指定引用和名称来构造对象 |
public void run() | 若使用Runnable引用构造了线程对象,调用该方法时最终调 用接口中的版本 若没有使用Runnable引用构造线程对象,调用该方法时则啥也不做 |
public void start() | 用于启动线程,Java虚拟机会自动调用该线程的run方法 |
public long getId() | 获取调用对象所表示线程的编号 |
public String getName() | 获取调用对象所表示线程的名称 |
public void setName(String name) | 设置/修改线程的名称为参数指定的数值 |
public static Thread currentThread() | 获取当前正在执行线程的引用 |
2.1、继承Thread类
- 优点:实现起来简单,而且要获取当前线程,无需调用Thread.currentThread()方法,直接使用this即可获取当前线程
- 缺点:线程类已经继承Thread类了,就不能再继承其他类,多个线程不能共享同一份资源
public class MyThread extends Thread {
@Override
public void run() {
for (int i = 0; i < 50; i++) {
System.out.println(this.getName()+"----------------"+i);
}
}
}
public class Test {
public static void main(String[] args) {
new MyThread().start();
for (int i = 0; i < 50; i++) {
System.out.println(Thread.currentThread().getName()+"----------------"+i);
}
}
}
注:直接调用run方法如同调用类成员方法一样
2.2、实现Runnable接口
- 优点:线程类只是实现了接口,还可以继承其他类,多个线程可以使用同一个target对象,适合多个线程处理同一份资源的情况
- 缺点:通过这种方式实现多线程,相较于第一类方式,编程较复杂,要访问当前线程,必须调用Thread.currentThread()方法
public class MyRunable implements Runnable {
@Override
public void run() {
for (int i = 0; i < 50; i++) {
System.out.println(Thread.currentThread().getName()+"----------------"+i);
}
}
}
public class Test {
public static void main(String[] args) {
new Thread(new MyRunable()).start();
for (int i = 0; i < 50; i++) {
System.out.println(Thread.currentThread().getName()+"----------------"+i);
}
}
}
2.3、Callable和FutureTask
- 优点:线程类只是实现了接口,还可以继承其他类,多个线程可以使用同一个target对象,适合多个线程处理同一份资源的情况
- 缺点:通过这种方式实现多线程,相较于第一类方式,编程较复杂,要访问当前线程,必须调用Thread.currentThread()方法
public class Test {
public static void main(String[] args) throws ExecutionException, InterruptedException {
FutureTask<Integer> futureTask=new FutureTask<Integer>(new Callable<Integer>() {
@Override
public Integer call() throws Exception {
for (int i = 0; i < 50; i++) {
System.out.println(Thread.currentThread().getName()+"----------------"+i);
}
return 100;
}
});
new Thread(futureTask, "ruoye").start();
for (int i = 0; i < 50; i++) {
System.out.println(Thread.currentThread().getName()+"----------------"+i);
}
System.out.println(futureTask.get());
}
}
lambda表达式
public class Test {
public static void main(String[] args) throws ExecutionException, InterruptedException {
FutureTask<Integer> futureTask = new FutureTask<>((Callable<Integer>) () -> {
System.out.println("hello world!");
return 100;
});
new Thread(futureTask, "ruoye").start();
for (int i = 0; i < 50; i++) {
System.out.println(Thread.currentThread().getName()+"----------------"+i);
}
System.out.println(futureTask.get());
}
}
3、线程优先级及线程让步
方法声明 | 功能介绍 |
---|---|
public static void yield() | 当前线程让出处理器(离开Running状态),使当前线程进入Runnable 状态等待 |
public static void sleep(times) | 使当前线程从 Running 放弃处理器进入Block状态, 休眠times毫秒 |
public int getPriority() | 获取线程的优先级 |
public void setPriority(int newPriority) | 修改线程的优先级,优先级越高的线程不一定先执行,但该线程获取到时间片的机会会更多 一些 |
public void join() | 等待该线程终止 |
public void join(long millis) | 等待参数指定的毫秒数 |
public boolean isDaemon() | 用于判断是否为守护线程 |
public void setDaemon(boolean on) | 用于设置线程为守护线程 |
sleep
public class Test {
public static void main(String[] args) {
SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
while (true){
System.out.println(simpleDateFormat.format(new Date()));
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
setPriority线程优先级
public class Test {
public static void main(String[] args) {
Thread thread = new Thread(() -> {
System.out.println(Thread.currentThread().getName()+"优先级-----"+Thread.currentThread().getPriority());
for (int i = 0; i < 100; i++) {
System.out.println(Thread.currentThread().getName()+"-----"+i);
}
});
thread.setName("ruoye");
thread.setPriority(Thread.MAX_PRIORITY);
thread.start();
for (int i = 0; i < 100; i++) {
System.out.println(Thread.currentThread().getName()+"-----"+i);
}
}
}
线程等待
public class Test {
public static void main(String[] args) throws InterruptedException {
Thread thread = new Thread(() -> {
for (int i = 0; i < 10; i++) {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+"-----"+i);
}
});
thread.setName("ruoye");
thread.start();
// thread.join();
// System.out.println("终于等到你");
thread.join(5000);
System.out.println("没有等到你");
}
}
守护线程
public class Test {
public static void main(String[] args) throws InterruptedException {
Thread thread = new Thread(() -> {
for (int i = 0; i < 10; i++) {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+"-----"+i);
}
});
thread.setName("ruoye");
thread.setDaemon(true);
thread.start();
Thread.sleep(5000);
System.out.println("没有等到你");
}
}
4、线程同步
4.1、多线程出现的问题
public class Account implements Runnable {
private int money;
public Account(int money) {
this.money = money;
}
public int getMoney() {
return money;
}
public void setMoney(int money) {
this.money = money;
}
@Override
public void run() {
System.out.println("进到门口");
System.out.println("开始取钞");
if (this.money>200){
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
this.money-=200;
System.out.println("取款成功");
}
}
@Override
public String toString() {
return "Account{" +
"money=" + money +
'}';
}
}
public class Test {
public static void main(String[] args) throws InterruptedException {
Account account = new Account(1000);
Thread thread = new Thread(account);
Thread thread1 = new Thread(account);
thread.start();
thread1.start();
thread.join();
thread1.join();
System.out.println(account.getMoney());
}
}
4.2、synchronized同步锁
4.2.1、synchronized代码块
下面所示为锁class,锁Account对象里的成员变量(对象)也可,但请时刻记住,多个Account为对象里的成员变量(对象)多个对象,那么就拥有了多把锁,此时应当用static修饰
休眠在同步代码块内不会让出cpu
public class Account implements Runnable {
private int money;
public Account(int money) {
this.money = money;
}
public int getMoney() {
return money;
}
public void setMoney(int money) {
this.money = money;
}
@Override
public void run() {
System.out.println("进到门口");
synchronized (Account.class){
System.out.println("开始取钞");
if (this.money>200){
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
this.money-=200;
System.out.println("取款成功");
}
}
}
@Override
public String toString() {
return "Account{" +
"money=" + money +
'}';
}
}
public class Test {
public static void main(String[] args) throws InterruptedException {
Account account = new Account(1000);
Thread thread = new Thread(account);
Thread thread1 = new Thread(account);
thread.start();
thread1.start();
thread.join();
thread1.join();
System.out.println(account.getMoney());
}
}
4.2.2、synchronized方法
当synchronized位于成员方法上等价于synchronized (this)
当当synchronized位于成员方法上等价于synchronized (类对象)
public class Account implements Runnable {
private int money;
public Account(int money) {
this.money = money;
}
public int getMoney() {
return money;
}
public void setMoney(int money) {
this.money = money;
}
@Override
public synchronized void run() {
System.out.println("进到门口");
System.out.println("开始取钞");
if (this.money>200){
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
this.money-=200;
System.out.println("取款成功");
}
}
@Override
public String toString() {
return "Account{" +
"money=" + money +
'}';
}
}
public class Test {
public static void main(String[] args) throws InterruptedException {
Account account = new Account(1000);
Thread thread = new Thread(account);
Thread thread1 = new Thread(account);
thread.start();
thread1.start();
thread.join();
thread1.join();
System.out.println(account.getMoney());
}
}
4.3、死锁问题
尽量减少同步的资源,减少同步代码块的嵌套结构的使用
线程一执行的代码
public void run(){
synchronized(a){
//持有对象锁a,等待对象锁b
synchronized(b){
//编写锁定的代码;
}
}
}
线程二执行的代码
public void run(){
synchronized(b){
//持有对象锁a,等待对象锁b
synchronized(a){
//编写锁定的代码;
}
}
}
4.4、Lock锁
- Lock是显式锁,需要手动实现开启和关闭操作,而synchronized是隐式锁,执行锁定代码后自动释放
- Lock只有同步代码块方式的锁,而synchronized有同步代码块方式和同步方法两种锁
- 使用Lock锁方式时,Java虚拟机将花费较少的时间来调度线程,因此性能更好
public class Account implements Runnable {
private int money;
private static Lock lock=new ReentrantLock();
public Account(int money) {
this.money = money;
}
public int getMoney() {
return money;
}
public void setMoney(int money) {
this.money = money;
}
@Override
public void run() {
lock.lock();
System.out.println("进到门口");
System.out.println("开始取钞");
if (this.money>200){
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
this.money-=200;
System.out.println("取款成功");
}
lock.unlock();
}
@Override
public String toString() {
return "Account{" +
"money=" + money +
'}';
}
}
public class Test {
public static void main(String[] args) throws InterruptedException {
Account account = new Account(1000);
Thread thread = new Thread(account);
Thread thread1 = new Thread(account);
thread.start();
thread1.start();
thread.join();
thread1.join();
System.out.println(account.getMoney());
}
}
5、线程通信
5.1、线程通信
不能锁class
public class Account implements Runnable {
private int a;
public Account(int a) {
this.a = a;
}
@Override
public void run() {
while (true){
synchronized (this) {
if (a<100){
System.out.println(Thread.currentThread().getName()+"========"+a);
a++;
notify();
try {
wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}else{
break;
}
}
}
}
}
public class Test {
public static void main(String[] args) throws InterruptedException {
Account account = new Account(1);
Thread ruoye = new Thread(account, "ruoye");
Thread yoya = new Thread(account, "yoya");
ruoye.start();
yoya.start();
}
}
5.2、生产者消费者问题
- 线程间的通信共享数据一定要有同步代码块synchronized
- 一定要有wait和notify,而且二者一定是成对出现
- 生产者和消费者的线程实现一定是在while(true)里面
public class Mother implements Runnable {
private Account account;
public Mother(Account account) {
this.account = account;
}
@Override
public void run() {
while (true){
try {
account.produce();
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
public class Ming implements Runnable {
private Account account;
public Ming(Account account) {
this.account = account;
}
@Override
public void run() {
while (true){
try {
account.consumer();
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
public class Account {
private int a;
public Account(int a) {
this.a = a;
}
public int getA() {
return a;
}
public void setA(int a) {
this.a = a;
}
public synchronized void produce() throws InterruptedException {
notify();
if (a<2000){
a+=100;
System.out.println("妈妈给小明存了100元");
}else{
wait();
}
}
public synchronized void consumer() throws InterruptedException {
notify();
if (a>75){
a-=75;
System.out.println("小明花了75元");
}else{
wait();
}
}
}
public class Test {
public static void main(String[] args) throws InterruptedException {
Account account = new Account(0);
new Thread(new Mother(account)).start();
new Thread(new Ming(account)).start();
}
}
相关文章
- java中scanner意思_Java中的Scanner
- java socket发送中文乱码_java Socket接收数据乱码问题「建议收藏」
- java技术介绍_Java技术汇总
- Java中将xml文件转化为json的两种方式
- 面试官:单核 CPU 支持 Java 多线程吗?为什么?被问懵了!
- Java cast_java concat方法
- java在线生成uuid_Java生成uuid
- Java多线程
- Flink使用Table和SQL语法操作Hive(Java版)
- 【Java 语言】Java 多线程 一 ( 线程基础 : 线程启动 | 线程停止 | 线程暂停 | 线程优先级 | 守护线程)
- Java学习笔记 基础知识(注释、基本数据类型)
- 2018跳槽面试必备之深入理解 Java 多线程核心知识详解编程语言
- java多线程示例 模拟生产者消费者详解编程语言
- Java学习笔记之二十七Java8中传多个参数时的方法详解编程语言
- java多线程系列(八)—CountDownLatch和CyclicBarrie详解编程语言
- Java实现MSSQL数据库连接(java连接mssql)
- java 线程池 spring线程池 多线程知识总结详解编程语言
- MySQL与Java互调:构建高效业务系统(mysql调用java)
- Java轻松使用Redis实现数据高效存储(java使用redis)
- 机制Redis Java过期机制:优化存储速率(redisjava过期)
- Java AMF3曝远程代码执行漏洞
- Linux下编译Java文件,迎来新体验(linux编译java文件)
- 实现Java认证让你离Oracle更近一步(java认证oracle)
- [JAVA]十四种Java开发工具点评
- Java多线程编程之限制优先级